diff options
448 files changed, 7276 insertions, 2329 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index 13903acc0439..f429966e042a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -56,6 +56,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; +import com.android.modules.expresslog.Counter; import com.android.server.LocalServices; import com.android.server.job.GrantedUriPermissions; import com.android.server.job.JobSchedulerInternal; @@ -161,6 +162,9 @@ public final class JobStatus { /** If the job is going to be passed an unmetered network. */ private boolean mHasAccessToUnmetered; + /** If the effective bucket has been downgraded once due to being buggy. */ + private boolean mIsDowngradedDueToBuggyApp; + /** * The additional set of dynamic constraints that must be met if this is an expedited job that * had a long enough run while the device was Dozing or in battery saver. @@ -1173,18 +1177,32 @@ public final class JobStatus { // like other ACTIVE apps. return ACTIVE_INDEX; } + + final int bucketWithMediaExemption; + if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX + && mHasMediaBackupExemption) { + // Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since + // media backup jobs are important to the user, and the source package may not have + // been used directly in a while. + bucketWithMediaExemption = Math.min(WORKING_INDEX, actualBucket); + } else { + bucketWithMediaExemption = actualBucket; + } + // If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket // (potentially because it's used frequently by the user), limit its effective bucket // so that it doesn't get to run as much as a normal ACTIVE app. - final int highestBucket = isBuggy ? WORKING_INDEX : ACTIVE_INDEX; - if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX - && mHasMediaBackupExemption) { - // Treat it as if it's at least WORKING_INDEX since media backup jobs are important - // to the user, and the - // source package may not have been used directly in a while. - return Math.max(highestBucket, Math.min(WORKING_INDEX, actualBucket)); + if (isBuggy && bucketWithMediaExemption < WORKING_INDEX) { + if (!mIsDowngradedDueToBuggyApp) { + // Safety check to avoid logging multiple times for the same job. + Counter.logIncrementWithUid( + "job_scheduler.value_job_quota_reduced_due_to_buggy_uid", + getTimeoutBlameUid()); + mIsDowngradedDueToBuggyApp = true; + } + return WORKING_INDEX; } - return Math.max(highestBucket, actualBucket); + return bucketWithMediaExemption; } /** Returns the real standby bucket of the job. */ diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 2e40f6096ccb..912e8df6bdc7 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -144,6 +144,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private Context mContext; private IAuthService mService; + // LINT.IfChange /** * Creates a builder for a {@link BiometricPrompt} dialog. * @param context The {@link Context} that will be used to build the prompt. @@ -417,6 +418,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @hide */ @NonNull + @RequiresPermission(anyOf = {USE_BIOMETRIC_INTERNAL}) public Builder setDisallowBiometricsIfPolicyExists(boolean checkDevicePolicyManager) { mPromptInfo.setDisallowBiometricsIfPolicyExists(checkDevicePolicyManager); return this; @@ -429,6 +431,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @hide */ @NonNull + @RequiresPermission(anyOf = {USE_BIOMETRIC_INTERNAL}) public Builder setReceiveSystemEvents(boolean set) { mPromptInfo.setReceiveSystemEvents(set); return this; @@ -442,6 +445,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @hide */ @NonNull + @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL}) public Builder setIgnoreEnrollmentState(boolean ignoreEnrollmentState) { mPromptInfo.setIgnoreEnrollmentState(ignoreEnrollmentState); return this; @@ -454,10 +458,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @hide */ @NonNull + @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL}) public Builder setIsForLegacyFingerprintManager(int sensorId) { mPromptInfo.setIsForLegacyFingerprintManager(sensorId); return this; } + // LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java) /** * Creates a {@link BiometricPrompt}. diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java index 02aad1dc4b4b..e27507874167 100644 --- a/core/java/android/hardware/biometrics/PromptInfo.java +++ b/core/java/android/hardware/biometrics/PromptInfo.java @@ -113,6 +113,7 @@ public class PromptInfo implements Parcelable { dest.writeBoolean(mIsForLegacyFingerprintManager); } + // LINT.IfChange public boolean containsTestConfigurations() { if (mIsForLegacyFingerprintManager && mAllowedSensorIds.size() == 1 @@ -122,6 +123,10 @@ public class PromptInfo implements Parcelable { return true; } else if (mAllowBackgroundAuthentication) { return true; + } else if (mIsForLegacyFingerprintManager) { + return true; + } else if (mIgnoreEnrollmentState) { + return true; } return false; } @@ -144,6 +149,7 @@ public class PromptInfo implements Parcelable { } return false; } + // LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/BiometricPrompt.java) // Setters diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index dbc1be141571..d9ac4850e924 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -868,6 +868,11 @@ public abstract class WallpaperService extends Service { * This will trigger a {@link #onComputeColors()} call. */ public void notifyColorsChanged() { + if (mDestroyed) { + Log.i(TAG, "Ignoring notifyColorsChanged(), Engine has already been destroyed."); + return; + } + final long now = mClockFunction.get(); if (now - mLastColorInvalidation < NOTIFY_COLORS_RATE_LIMIT_MS) { Log.w(TAG, "This call has been deferred. You should only call " @@ -2226,7 +2231,11 @@ public abstract class WallpaperService extends Service { } } - void detach() { + /** + * @hide + */ + @VisibleForTesting + public void detach() { if (mDestroyed) { return; } @@ -2442,6 +2451,14 @@ public abstract class WallpaperService extends Service { } public void reportShown() { + if (mEngine == null) { + Log.i(TAG, "Can't report null engine as shown."); + return; + } + if (mEngine.mDestroyed) { + Log.i(TAG, "Engine was destroyed before we could draw."); + return; + } if (!mShownReported) { mShownReported = true; Trace.beginSection("WPMS.mConnection.engineShown"); diff --git a/core/java/com/android/internal/os/TimeoutRecord.java b/core/java/com/android/internal/os/TimeoutRecord.java index a0e29347d07f..f8a5520c26d5 100644 --- a/core/java/com/android/internal/os/TimeoutRecord.java +++ b/core/java/com/android/internal/os/TimeoutRecord.java @@ -58,6 +58,7 @@ public class TimeoutRecord { int APP_REGISTERED = 7; int SHORT_FGS_TIMEOUT = 8; int JOB_SERVICE = 9; + int APP_START = 10; } /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */ @@ -186,4 +187,10 @@ public class TimeoutRecord { public static TimeoutRecord forJobService(String reason) { return TimeoutRecord.endingNow(TimeoutKind.JOB_SERVICE, reason); } + + /** Record for app startup timeout. */ + @NonNull + public static TimeoutRecord forAppStart(String reason) { + return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason); + } } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index e0183931777b..1b1efeed5ff2 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1035,7 +1035,7 @@ public class LockPatternUtils { CREDENTIAL_TYPE_API, CREDENTIAL_TYPE_API, mCredentialTypeQuery); /** - * Invalidate the credential cache + * Invalidate the credential type cache * @hide */ public final static void invalidateCredentialTypeCache() { diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 208d5a6d6973..f5d73f9021c0 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan nie toegang tot die foon se kamera op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan nie toegang tot die tablet se kamera op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Jy kan nie toegang hiertoe kry terwyl daar gestroom word nie. Probeer eerder op jou foon."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan nie prent-in-prent sien terwyl jy stroom nie"</string> <string name="system_locale_title" msgid="711882686834677268">"Stelselverstek"</string> <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Metgeselhorlosieprofiel se toestemming om horlosies te bestuur"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 231f4b2a0987..9b306818356f 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"የስልኩን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ጡባዊውን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ዥረት በመልቀቅ ላይ ሳለ ይህ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"በዥረት በመልቀቅ ወቅት በሥዕል-ላይ-ሥዕል ማየት አይችሉም"</string> <string name="system_locale_title" msgid="711882686834677268">"የሥርዓት ነባሪ"</string> <string name="default_card_name" msgid="9198284935962911468">"ካርድ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"የእጅ ሰዓቶችን ለማስተዳደር የአጃቢ የእጅ ሰዓት መገለጫ ፍቃድ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index c71ee6354323..f480d3a0581e 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -2315,6 +2315,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"يتعذّر الوصول إلى كاميرا الهاتف من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"يتعذّر الوصول إلى كاميرا الجهاز اللوحي من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string> <string name="vdm_secure_window" msgid="161700398158812314">"لا يمكن الوصول إلى هذا المحتوى أثناء البث. بدلاً من ذلك، جرِّب استخدام هاتفك."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"لا يمكن عرض نافذة ضمن النافذة أثناء البث."</string> <string name="system_locale_title" msgid="711882686834677268">"الإعداد التلقائي للنظام"</string> <string name="default_card_name" msgid="9198284935962911468">"رقم البطاقة <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"إذن الملف الشخصي في Companion Watch لإدارة الساعات"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 4c63a20c96f7..15563c177eeb 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা ফ’নটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা টেবলেটটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ষ্ট্ৰীম কৰি থকাৰ সময়ত এইটো এক্সেছ কৰিব নোৱাৰি। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ষ্ট্ৰীম কৰি থকাৰ সময়ত picture-in-picture চাব নোৱাৰি"</string> <string name="system_locale_title" msgid="711882686834677268">"ছিষ্টেম ডিফ’ল্ট"</string> <string name="default_card_name" msgid="9198284935962911468">"কাৰ্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ঘড়ী পৰিচালনা কৰিবলৈ সহযোগী ঘড়ীৰ প্ৰ’ফাইলৰ অনুমতি"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 6a9f5fed9f51..d7bec0613265 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına giriş etmək olmur"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan planşetin kamerasına giriş etmək olmur"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Yayım zamanı buna giriş mümkün deyil. Telefonunuzda sınayın."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Yayım zamanı şəkildə şəkilə baxmaq mümkün deyil"</string> <string name="system_locale_title" msgid="711882686834677268">"Sistem defoltu"</string> <string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Saatları idarə etmək üçün Kompanyon Saat profili icazəsi"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 8e09389b182a..a6254f628f02 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ne može da se pristupi kameri telefona sa <xliff:g id="DEVICE">%1$s</xliff:g> uređaja"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ne može da se pristupi kameri tableta sa <xliff:g id="DEVICE">%1$s</xliff:g> uređaja"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Ovom ne možete da pristupate tokom strimovanja. Probajte na telefonu."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ne možete da gledate sliku u slici pri strimovanju"</string> <string name="system_locale_title" msgid="711882686834677268">"Podrazumevani sistemski"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Dozvola za profil pratećeg sata za upravljanje satovima"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 538e1267fb44..624de9c04c47 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не ўдалося атрымаць доступ да камеры тэлефона з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не ўдалося атрымаць доступ да камеры планшэта з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string> <string name="vdm_secure_window" msgid="161700398158812314">"Не ўдаецца атрымаць доступ у час перадачы плынню. Паспрабуйце скарыстаць тэлефон."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Падчас перадачы плынню прагляд у рэжыме \"Відарыс у відарысе\" немагчымы"</string> <string name="system_locale_title" msgid="711882686834677268">"Стандартная сістэмная налада"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дазвол для спадарожнай праграмы кіраваць гадзіннікамі"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 9b00b2ca70c8..a71c0af44f37 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Няма достъп до камерата на телефона от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Няма достъп до камерата на таблета от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"До това съдържание не може да се осъществи достъп при поточно предаване. Вместо това опитайте от телефона си."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Функцията „Картина в картината“ не е налице при поточно предаване"</string> <string name="system_locale_title" msgid="711882686834677268">"Стандартно за системата"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Разрешение на придружаващото приложение за достъп до потребителския профил на часовника с цел управление на часовници"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index bf5ad8d15e8c..ea0b94951fcc 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপনার <xliff:g id="DEVICE">%1$s</xliff:g> থেকে ফোনের ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপনার <xliff:g id="DEVICE">%1$s</xliff:g> থেকে ট্যাবলেটের ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string> <string name="vdm_secure_window" msgid="161700398158812314">"স্ট্রিমিংয়ের সময় এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"স্ট্রিম করার সময় \'ছবির-মধ্যে-ছবি\' দেখা যাবে না"</string> <string name="system_locale_title" msgid="711882686834677268">"সিস্টেম ডিফল্ট"</string> <string name="default_card_name" msgid="9198284935962911468">"কার্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ওয়াচ ম্যানেজ করতে, কম্প্যানিয়ন ওয়াচ প্রোফাইল সংক্রান্ত অনুমতি"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index ab8789c701d1..afafa1c9a9df 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nije moguće pristupiti kameri telefona s uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nije moguće pristupiti kameri tableta s uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Ovom ne možete pristupiti tokom prijenosa. Umjesto toga pokušajte na telefonu."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tokom prijenosa nije moguće gledati sliku u slici"</string> <string name="system_locale_title" msgid="711882686834677268">"Sistemski zadano"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Odobrenje za profil pratećeg sata da upravlja satovima"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index ac37eb15d168..5264557a227a 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No es pot accedir a la càmera del telèfon des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No es pot accedir a la càmera de la tauleta des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"No s\'hi pot accedir mentre s\'està reproduint en continu. Prova-ho al telèfon."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"No es pot veure el mode d\'imatge sobre imatge durant la reproducció en continu"</string> <string name="system_locale_title" msgid="711882686834677268">"Valor predeterminat del sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"TARGETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permís del perfil del rellotge perquè l\'aplicació complementària gestioni els rellotges"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a517a18440b8..4510eff9a321 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ze zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze získat přístup k fotoaparátu telefonu"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ze zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze získat přístup k fotoaparátu tabletu"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Tento obsah při streamování nelze zobrazit. Zkuste to na telefonu."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Během streamování nelze zobrazit obraz v obraze"</string> <string name="system_locale_title" msgid="711882686834677268">"Výchozí nastavení systému"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Oprávnění profilu doprovodných hodinek ke správě hodinek"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 01ecd96625ad..2f6253120a86 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kameraet på din telefon kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kameraet på din tablet kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Der er ikke adgang til dette indhold under streaming. Prøv på din telefon i stedet."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Funktionen Integreret billede er ikke tilgængelig, når der streames"</string> <string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string> <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Tilladelse til at administrere ure for urprofilens medfølgende app"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 4430ef2f1217..713a62f741aa 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Zugriff auf die Kamera des Smartphones über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Zugriff auf die Kamera des Tablets über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Während des Streamings ist kein Zugriff möglich. Versuch es stattdessen auf deinem Smartphone."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Funktion „Bild im Bild“ kann beim Streamen nicht verwendet werden"</string> <string name="system_locale_title" msgid="711882686834677268">"Standardeinstellung des Systems"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Berechtigung für Companion-Smartwatch-Profil zum Verwalten von Smartwatches"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index d9051a4f54ba..a58b78028042 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Δεν είναι δυνατή η πρόσβαση στην κάμερα τηλεφώνου από το <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Δεν είναι δυνατή η πρόσβαση στην κάμερα του tablet από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Δεν είναι δυνατή η πρόσβαση σε αυτό το στοιχείο κατά τη ροή. Δοκιμάστε στο τηλέφωνό σας."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Δεν είναι δυνατή η προβολή picture-in-picture κατά τη ροή"</string> <string name="system_locale_title" msgid="711882686834677268">"Προεπιλογή συστήματος"</string> <string name="default_card_name" msgid="9198284935962911468">"ΚΑΡΤΑ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Άδεια προφίλ συνοδευτικής εφαρμογής ρολογιού για τη διαχείριση ρολογιών"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 1feb601d1ce5..2a5847c911d9 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"System default"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion watch profile permission to manage watches"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 037c55d8d771..19424289b8a9 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"System default"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion Watch profile permission to manage watches"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index cdf3677265b0..45b09f5d84ab 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"System default"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion watch profile permission to manage watches"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 8952bdc3342e..81145e8fb299 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"System default"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion watch profile permission to manage watches"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 749b2fffb0ea..54d02784ae39 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"System default"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion Watch profile permission to manage watches"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 56aaf5af22f4..fcb3f08d09eb 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del dispositivo desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara de la tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una transmisión. Inténtalo en tu teléfono."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"No puedes ver pantalla en pantalla mientras transmites"</string> <string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permiso de perfil del reloj complementario para administrar relojes"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 47cf2cc5af79..4c5939c055b6 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del teléfono desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara del tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una emisión. Prueba en tu teléfono."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"No se puede usar imagen en imagen mientras se emite contenido"</string> <string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permiso del perfil del reloj complementario para gestionar relojes"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 3bd876fef14c..df2e2aff712f 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tahvelarvuti kaamerale juurde"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Sellele ei pääse voogesituse ajal juurde. Proovige juurde pääseda oma telefonis."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Voogesitamise ajal ei saa pilt pildis funktsiooni kasutada"</string> <string name="system_locale_title" msgid="711882686834677268">"Süsteemi vaikeseade"</string> <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kaasrakenduse profiili luba kellade haldamiseks"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 5b7741fb3627..f5e6948f186e 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -671,7 +671,7 @@ <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Sakatu hau aurpegi-eredua ezabatzeko eta, gero, gehitu aurpegia berriro"</string> <string name="face_setup_notification_title" msgid="8843461561970741790">"Konfiguratu Aurpegi bidez desblokeatzea"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Telefonoa desblokeatzeko, begira iezaiozu"</string> - <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Aurpegi bidez desblokeatzeko aukera erabiltzeko, aktibatu "<b>"kamera erabiltzeko baimena"</b>" Ezarpenak > Pribatutasuna atalean"</string> + <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Aurpegi bidez desblokeatzeko eginbidea erabiltzeko, aktibatu "<b>"kamera erabiltzeko baimena"</b>" Ezarpenak > Pribatutasuna atalean"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfiguratu telefonoa desblokeatzeko modu gehiago"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Sakatu hau hatz-marka bat gehitzeko"</string> <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Hatz-marka bidez desblokeatzea"</string> @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ezin da atzitu telefonoaren kamera <xliff:g id="DEVICE">%1$s</xliff:g> gailutik"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ezin da atzitu tabletaren kamera <xliff:g id="DEVICE">%1$s</xliff:g> gailutik"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Ezin da atzitu edukia hura igorri bitartean. Oraingo gailuaren ordez, erabili telefonoa."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Edukia zuzenean erreproduzitu bitartean ezin da pantaila txiki gainjarrian ikusi"</string> <string name="system_locale_title" msgid="711882686834677268">"Sistemaren balio lehenetsia"</string> <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> TXARTELA"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Aplikazio osagarrien erloju-profilaren baimena erlojuak kudeatzeko"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index ad027bc2924b..226be578086d 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"از <xliff:g id="DEVICE">%1$s</xliff:g> به دوربین تلفن دسترسی ندارید"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"نمیتوان از <xliff:g id="DEVICE">%1$s</xliff:g> شما به دوربین رایانه لوحی دسترسی داشت"</string> <string name="vdm_secure_window" msgid="161700398158812314">"درحین جاریسازی، نمیتوانید به آن دسترسی داشته باشید. دسترسی به آن را در تلفنتان امتحان کنید."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"هنگام جاریسازی نمیتوان تصویر در تصویر را مشاهده کرد"</string> <string name="system_locale_title" msgid="711882686834677268">"پیشفرض سیستم"</string> <string name="default_card_name" msgid="9198284935962911468">"کارت <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"اجازه نمایه «ساعت همراه» برای مدیریت ساعتها"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 319193d820f5..b88abb08bd73 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse puhelimen kameraan"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tabletin kameraan"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Sisältöön ei saa pääsyä striimauksen aikana. Kokeile striimausta puhelimella."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Pikkuruutua ei voi nähdä striimauksen aikana"</string> <string name="system_locale_title" msgid="711882686834677268">"Järjestelmän oletusarvo"</string> <string name="default_card_name" msgid="9198284935962911468">"Kortti: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kumppanin kelloprofiilin hallintalupa"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index ea51b7f9957f..02bc75ca2aec 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Vous ne pouvez pas y accéder lorsque vous utilisez la diffusion en continu. Essayez sur votre téléphone à la place."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher des incrustations d\'image pendant une diffusion en continu"</string> <string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string> <string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorisation du profil de la montre de l\'application compagnon pour gérer les montres"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index a1d43836bf53..e922931a0de3 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Impossible d\'accéder à cela pendant le streaming. Essayez plutôt sur votre téléphone."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher Picture-in-picture pendant le streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string> <string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorisation du profil de la montre associée pour gérer des montres"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 73527bf488df..729f77101bf5 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -256,7 +256,7 @@ <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Usa esta opción na maioría das circunstancias. Permíteche realizar un seguimento do progreso do informe, introducir máis detalles sobre o problema e facer capturas de pantalla. É posible que omita algunhas seccións menos usadas para as que se tarda máis en facer o informe."</string> <string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe completo"</string> <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Usa esta opción para que a interferencia sexa mínima cando o teu dispositivo non responda ou funcione demasiado lento, ou ben cando precises todas as seccións do informe. Non poderás introducir máis detalles nin facer máis capturas de pantalla."</string> - <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Vaise facer unha captura de pantalla para o informe de erro dentro de # segundo.}other{Vaise facer unha captura de pantalla para o informe de erro dentro de # segundos.}}"</string> + <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Vaise facer unha captura de pantalla para o informe de erros dentro de # segundo.}other{Vaise facer unha captura de pantalla para o informe de erros dentro de # segundos.}}"</string> <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Realizouse a captura de pantalla co informe de erros"</string> <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Produciuse un erro ao realizar a captura de pantalla co informe de erros"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string> @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Non se puido acceder á cámara do teléfono desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Non se puido acceder á cámara da tableta desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Non se puido acceder a este contido durante a reprodución en tempo real. Téntao desde o teléfono."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Non se pode ver un vídeo en pantalla superposta mentres se reproduce en tempo real"</string> <string name="system_locale_title" msgid="711882686834677268">"Opción predeterminada do sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"TARXETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permiso de perfil de Companion Watch para xestionar reloxos"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 692b70ddf7e1..9531ff82f48e 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ફોનના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ટૅબ્લેટના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string> <string name="vdm_secure_window" msgid="161700398158812314">"સ્ટ્રીમ કરતી વખતે આ ઍક્સેસ કરી શકાતું નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"સ્ટ્રીમ કરતી વખતે ચિત્ર-માં-ચિત્ર જોઈ શકતા નથી"</string> <string name="system_locale_title" msgid="711882686834677268">"સિસ્ટમ ડિફૉલ્ટ"</string> <string name="default_card_name" msgid="9198284935962911468">"કાર્ડ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"વૉચ મેનેજ કરવા માટે સાથી વૉચ પ્રોફાઇલની પરવાનગી"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 8d41c04e6f59..bed4cfaabeff 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"आपके <xliff:g id="DEVICE">%1$s</xliff:g> से फ़ोन के कैमरे को ऐक्सेस नहीं किया जा सकता"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"आपके <xliff:g id="DEVICE">%1$s</xliff:g> से टैबलेट के कैमरे को ऐक्सेस नहीं किया जा सकता"</string> <string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रीमिंग के दौरान, इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर ऐक्सेस करके देखें."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रीमिंग करते समय, \'पिक्चर में पिक्चर\' सुविधा इस्तेमाल नहीं की जा सकती"</string> <string name="system_locale_title" msgid="711882686834677268">"सिस्टम डिफ़ॉल्ट"</string> <string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"स्मार्टवॉच मैनेज करने के लिए, स्मार्टवॉच के साथ काम करने वाले साथी ऐप्लिकेशन पर प्रोफ़ाइल से जुड़ी अनुमति"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 817efed0900e..b4c5cd4c42e1 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"S vašeg uređaja <xliff:g id="DEVICE">%1$s</xliff:g> nije moguće pristupiti fotoaparatu telefona"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"S vašeg uređaja <xliff:g id="DEVICE">%1$s</xliff:g> nije moguće pristupiti fotoaparatu tableta"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Sadržaju nije moguće pristupiti tijekom streaminga. Pokušajte mu pristupiti na telefonu."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Slika u slici ne može se prikazivati tijekom streaminga"</string> <string name="system_locale_title" msgid="711882686834677268">"Zadane postavke sustava"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Dopuštenje profila popratne aplikacije sata za upravljanje satovima"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 1916a52cd5b6..0f364edb63d2 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nem lehet hozzáférni a telefon kamerájához a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nem lehet hozzáférni a táblagép kamerájához a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Ehhez a tartalomhoz nem lehet hozzáférni streamelés közben. Próbálja újra a telefonján."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Streamelés közben nem lehetséges a kép a képben módban való lejátszás"</string> <string name="system_locale_title" msgid="711882686834677268">"Rendszerbeállítás"</string> <string name="default_card_name" msgid="9198284935962911468">"KÁRTYA: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Társóra-profilra vonatkozó engedély az órák kezeléséhez"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 5491f3446900..33a90c251e7a 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Հնարավոր չէ օգտագործել հեռախոսի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Հնարավոր չէ օգտագործել պլանշետի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Այս բովանդակությունը հասանելի չէ հեռարձակման ընթացքում։ Օգտագործեք ձեր հեռախոսը։"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Հեռարձակման ժամանակ հնարավոր չէ դիտել նկարը նկարի մեջ"</string> <string name="system_locale_title" msgid="711882686834677268">"Կանխադրված"</string> <string name="default_card_name" msgid="9198284935962911468">"ՔԱՐՏ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Ժամացույցները կառավարելու թույլտվություն ուղեկցող հավելվածի համար"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 0ff21cbe9a93..d834470d79b2 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera ponsel dari <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet dari <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Konten ini tidak dapat diakses saat melakukan streaming. Coba di ponsel."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tidak dapat menampilkan picture-in-picture saat streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"Default sistem"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTU <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Izin profil Smartwatch Pendamping untuk mengelola smartwatch"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 3ba712075284..b3c802b42f7b 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ekki er hægt að opna myndavél símans úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ekki er hægt að opna myndavél spjaldtölvunnar úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Ekki er hægt að opna þetta á meðan streymi stendur yfir. Prófaðu það í símanum í staðinn."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ekki er hægt að horfa á mynd í mynd á meðan streymi er í gangi"</string> <string name="system_locale_title" msgid="711882686834677268">"Sjálfgildi kerfis"</string> <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Fylgiforrit úrs – prófílheimild til að stjórna úrum"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 39076f71980a..d18015494ace 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossibile accedere alla fotocamera del telefono dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossibile accedere alla fotocamera del tablet dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Impossibile accedere a questi contenuti durante lo streaming. Prova a usare il telefono."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossibile visualizzare Picture in picture durante lo streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"Predefinita di sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"SCHEDA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorizzazione per il profilo degli smartwatch complementari per gestire gli smartwatch"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 1dac7052c8a4..96a3618c5798 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"לא ניתן לגשת למצלמה של הטלפון מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"לא ניתן לגשת למצלמה של הטאבלט מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"אי אפשר לגשת לתוכן המאובטח הזה בזמן סטרימינג. במקום זאת, אפשר לנסות בטלפון."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"אי אפשר להציג תמונה בתוך תמונה בזמן סטרימינג"</string> <string name="system_locale_title" msgid="711882686834677268">"ברירת המחדל של המערכת"</string> <string name="default_card_name" msgid="9198284935962911468">"כרטיס <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"הרשאת פרופיל שעון לאפליקציה נלווית כדי לנהל שעונים"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 7f7104eb453d..5acb6c8989b7 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> からスマートフォンのカメラにアクセスできません"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> からタブレットのカメラにアクセスできません"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ストリーミング中はアクセスできません。スマートフォンでのアクセスをお試しください。"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ストリーミング中はピクチャー イン ピクチャーを表示できません"</string> <string name="system_locale_title" msgid="711882686834677268">"システムのデフォルト"</string> <string name="default_card_name" msgid="9198284935962911468">"カード <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ウォッチを管理できるコンパニオン ウォッチ プロファイル権限"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 8db1325a0a75..01bf9b0469c2 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ტელეფონის კამერაზე წვდომა ვერ მოხერხდა თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ტაბლეტის კამერაზე წვდომა ვერ მოხერხდა თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან"</string> <string name="vdm_secure_window" msgid="161700398158812314">"მასზე წვდომის მიᲦება შეუძლებელია სტრიმინგის დროს. ცადეთ ტელეფონიდან."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"სტრიმინგის დროს ეკრანის ეკრანში ნახვა შეუძლებელია"</string> <string name="system_locale_title" msgid="711882686834677268">"სისტემის ნაგულისხმევი"</string> <string name="default_card_name" msgid="9198284935962911468">"ბარათი <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"კომპანიონი საათის პროფილის ნებართვა საათების მართვაზე"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index df69e4ced740..06594088d789 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан телефон камерасын пайдалану мүмкін емес."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан планшет камерасын пайдалану мүмкін емес."</string> <string name="vdm_secure_window" msgid="161700398158812314">"Трансляция кезінде контентті көру мүмкін емес. Оның орнына телефоннан көріңіз."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Трансляция кезінде суреттегі суретті көру мүмкін емес."</string> <string name="system_locale_title" msgid="711882686834677268">"Жүйенің әдепкі параметрі"</string> <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g>-КАРТА"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Сағаттарды басқаруға арналған қосымша сағат профилінің рұқсаты"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 5328e5858297..549dce845e51 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"មិនអាចចូលប្រើកាមេរ៉ាទូរសព្ទពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានទេ"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"មិនអាចចូលប្រើកាមេរ៉ាថេប្លេតពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានទេ"</string> <string name="vdm_secure_window" msgid="161700398158812314">"មិនអាចចូលប្រើប្រាស់ខ្លឹមសារនេះបានទេ ពេលផ្សាយ។ សូមសាកល្បងប្រើនៅលើទូរសព្ទរបស់អ្នកជំនួសវិញ។"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"មិនអាចមើលរូបក្នុងរូបខណៈពេលកំពុងផ្សាយបានទេ"</string> <string name="system_locale_title" msgid="711882686834677268">"លំនាំដើមប្រព័ន្ធ"</string> <string name="default_card_name" msgid="9198284935962911468">"កាត <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ការអនុញ្ញាតពីកម្រងព័ត៌មាននាឡិកាដៃគូ ដើម្បីគ្រប់គ្រងនាឡិកា"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 2ce4b8cb8226..a103f086f765 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಮೂಲಕ ಫೋನ್ನ ಕ್ಯಾಮರಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಮೂಲಕ ಟ್ಯಾಬ್ಲೆಟ್ನ ಕ್ಯಾಮರಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ಸ್ಟ್ರೀಮ್ ಮಾಡುವಾಗ ಇದನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ಸ್ಟ್ರೀಮ್ ಮಾಡುವಾಗ ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ವೀಕ್ಷಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="system_locale_title" msgid="711882686834677268">"ಸಿಸ್ಟಂ ಡೀಫಾಲ್ಟ್"</string> <string name="default_card_name" msgid="9198284935962911468">"ಕಾರ್ಡ್ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ವಾಚ್ಗಳನ್ನು ನಿರ್ವಹಿಸುವುದಕ್ಕಾಗಿ ಕಂಪ್ಯಾನಿಯನ್ ವಾಚ್ ಪ್ರೊಫೈಲ್ ಅನುಮತಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 3485cc505b60..bbcf5098d96d 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1370,7 +1370,7 @@ <string name="usb_power_notification_message" msgid="7284765627437897702">"연결된 기기를 충전합니다. 옵션을 더 보려면 탭하세요."</string> <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"아날로그 오디오 액세서리가 감지됨"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"연결된 기기가 이 휴대전화와 호환되지 않습니다. 자세히 알아보려면 탭하세요."</string> - <string name="adb_active_notification_title" msgid="408390247354560331">"USB 디버깅 연결됨"</string> + <string name="adb_active_notification_title" msgid="408390247354560331">"USB 디버깅 연결됨."</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB 디버깅을 사용 중지하려면 탭하세요."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB 디버깅을 사용하지 않으려면 선택합니다."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"무선 디버깅 연결됨"</string> @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 휴대전화 카메라에 액세스할 수 없습니다."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 태블릿 카메라에 액세스할 수 없습니다."</string> <string name="vdm_secure_window" msgid="161700398158812314">"스트리밍 중에는 액세스할 수 없습니다. 대신 휴대전화에서 시도해 보세요."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"스트리밍 중에는 PIP 모드를 볼 수 없습니다."</string> <string name="system_locale_title" msgid="711882686834677268">"시스템 기본값"</string> <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> 카드"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"시계 관리를 위한 호환 시계 프로필 권한"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 3a572294f1a6..99c2ead7b0c6 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн телефондун камерасына мүмкүнчүлүк жок"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн планшетиңиздин камерасына мүмкүнчүлүк жок"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Муну алып ойнотуу учурунда көрүүгө болбойт. Анын ордуна телефондон кирип көрүңүз."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Алып ойнотуп жатканда сүрөттөгү сүрөт көрүнбөйт"</string> <string name="system_locale_title" msgid="711882686834677268">"Системанын демейки параметрлери"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Сааттын көмөкчү профилинин сааттарды тескөө уруксаты"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 00216777bc86..3a06f72d1cd1 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງໂທລະສັບຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງແທັບເລັດຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ບໍ່ສາມາດເຂົ້າເຖິງເນື້ອຫານີ້ໄດ້ໃນຂະນະທີ່ຍັງສະຕຣີມຢູ່. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ບໍ່ສາມາດເບິ່ງການສະແດງຜົນຊ້ອນກັນໃນຂະນະທີ່ສະຕຣີມໄດ້"</string> <string name="system_locale_title" msgid="711882686834677268">"ຄ່າເລີ່ມຕົ້ນຂອງລະບົບ"</string> <string name="default_card_name" msgid="9198284935962911468">"ບັດ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ສິດການອະນຸຍາດສຳລັບໂປຣໄຟລ໌ໃນໂມງຊ່ວຍເຫຼືອເພື່ອຈັດການໂມງ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 8e43d8a3a47a..f5530fe54097 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nepavyko pasiekti telefono fotoaparato iš „<xliff:g id="DEVICE">%1$s</xliff:g>“"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nepavyko pasiekti planšetinio kompiuterio fotoaparato iš „<xliff:g id="DEVICE">%1$s</xliff:g>“"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Nepavyksta pasiekti perduodant srautu. Pabandykite naudoti telefoną."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Negalima peržiūrėti vaizdo vaizde perduodant srautu"</string> <string name="system_locale_title" msgid="711882686834677268">"Numatytoji sistemos vertė"</string> <string name="default_card_name" msgid="9198284935962911468">"KORTELĖ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Papildomos programos laikrodžio profilio leidimas valdyti laikrodžius"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 2257c25453f9..08865b3ece7b 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nevar piekļūt tālruņa kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nevar piekļūt planšetdatora kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string> <string name="vdm_secure_window" msgid="161700398158812314">"Straumēšanas laikā nevar piekļūt šim saturam. Mēģiniet tam piekļūt savā tālrunī."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Straumēšanas laikā nevar skatīt attēlu attēlā"</string> <string name="system_locale_title" msgid="711882686834677268">"Sistēmas noklusējums"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Palīglietotnes pulksteņa profila atļauja pārvaldīt pulksteņus"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 21950c01cb2e..b574380ce823 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се пристапи до камерата на вашиот телефон од <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се пристапи до камерата на вашиот таблет од <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"До ова не може да се пристапи при стриминг. Наместо тоа, пробајте на вашиот телефон."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Не може да се прикажува слика во слика при стримување"</string> <string name="system_locale_title" msgid="711882686834677268">"Стандарден за системот"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТИЧКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дозвола за профилот на придружен часовник за управување со часовници"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 2dac3e4b5cdd..7856654553d6 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഫോണിന്റെ ക്യാമറ ആക്സസ് ചെയ്യാനാകില്ല"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> എന്നതിൽ നിന്ന് ടാബ്ലെറ്റിന്റെ ക്യാമറ ആക്സസ് ചെയ്യാനാകില്ല"</string> <string name="vdm_secure_window" msgid="161700398158812314">"സ്ട്രീം ചെയ്യുമ്പോൾ ഇത് ആക്സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ഫോണിൽ ശ്രമിച്ച് നോക്കൂ."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"സ്ട്രീമിംഗിനിടെ ചിത്രത്തിനുള്ളിൽ ചിത്രം കാണാനാകില്ല"</string> <string name="system_locale_title" msgid="711882686834677268">"സിസ്റ്റം ഡിഫോൾട്ട്"</string> <string name="default_card_name" msgid="9198284935962911468">"കാർഡ് <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"വാച്ചുകൾ മാനേജ് ചെയ്യുന്നതിന് സഹകാരി ആപ്പിനുള്ള വാച്ച് പ്രൊഫൈൽ അനുമതി"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 81835779632d..ef4d07d0ce07 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Таны <xliff:g id="DEVICE">%1$s</xliff:g>-с утасны камерт хандах боломжгүй"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Таны <xliff:g id="DEVICE">%1$s</xliff:g>-с таблетын камерт хандах боломжгүй"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Стримингийн үед үүнд хандах боломжгүй. Оронд нь утас дээрээ туршиж үзнэ үү."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Дамжуулах явцад дэлгэц доторх дэлгэцийг үзэх боломжгүй"</string> <string name="system_locale_title" msgid="711882686834677268">"Системийн өгөгдмөл"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дэмжигч цагны профайлын цаг удирдах зөвшөөрөл"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 214403555d04..26108cc4938b 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वरून फोनचा कॅमेरा अॅक्सेस करू शकत नाही"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वरून टॅबलेटचा कॅमेरा अॅक्सेस करू शकत नाही"</string> <string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रीम करताना हे अॅक्सेस केले जाऊ शकत नाही. त्याऐवजी तुमच्या फोनवर अॅक्सेस करून पहा."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रीम होत असताना चित्रात-चित्र पाहू शकत नाही"</string> <string name="system_locale_title" msgid="711882686834677268">"सिस्टीम डीफॉल्ट"</string> <string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"वॉच व्यवस्थापित करण्यासाठी सहयोगी वॉच प्रोफाइलची परवानगी"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index c800be95bc28..12846f9d19ad 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera telefon daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Kandungan ini tidak boleh diakses semasa penstriman. Cuba pada telefon anda."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tidak dapat melihat gambar dalam gambar semasa penstriman"</string> <string name="system_locale_title" msgid="711882686834677268">"Lalai sistem"</string> <string name="default_card_name" msgid="9198284935962911468">"KAD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kebenaran profil Jam Tangan rakan untuk mengurus jam tangan"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index d2f7ef750135..0ba4c1f0a314 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"သင်၏ <xliff:g id="DEVICE">%1$s</xliff:g> မှ ဖုန်းကင်မရာကို သုံး၍မရပါ"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"သင်၏ <xliff:g id="DEVICE">%1$s</xliff:g> မှ တက်ဘလက်ကင်မရာကို သုံး၍မရပါ"</string> <string name="vdm_secure_window" msgid="161700398158812314">"တိုက်ရိုက်လွှင့်နေစဉ် ၎င်းကို မသုံးနိုင်ပါ။ ၎င်းအစား ဖုန်းတွင် စမ်းကြည့်ပါ။"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"တိုက်ရိုက်လွှင့်စဉ် နှစ်ခုထပ်၍ မကြည့်နိုင်ပါ"</string> <string name="system_locale_title" msgid="711882686834677268">"စနစ်မူရင်း"</string> <string name="default_card_name" msgid="9198284935962911468">"ကတ် <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"လက်ပတ်နာရီများစီမံရန် ‘တွဲဖက်နာရီ’ ပရိုဖိုင်ခွင့်ပြုချက်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index f2c5c7759bef..1aa7b719005a 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Det er ikke mulig å få tilgang til telefonkameraet fra <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Det er ikke mulig å få tilgang til kameraet på nettbrettet fra <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Dette er ikke tilgjengelig under strømming. Prøv på telefonen i stedet."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan ikke se bilde-i-bilde under strømming"</string> <string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string> <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Klokkeprofil-tillatelse for følgeapp for å administrere klokker"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 13c3c12c35ac..438fc7ac6a9e 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मार्फत फोनको क्यामेरा प्रयोग गर्न मिल्दैन"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मार्फत ट्याब्लेटको क्यामेरा प्रयोग गर्न मिल्दैन"</string> <string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रिम गरिरहेका बेला यो सामग्री हेर्न तथा प्रयोग गर्न मिल्दैन। बरु आफ्नो फोनमार्फत सो सामग्री हेर्ने तथा प्रयोग गर्ने प्रयास गर्नुहोस्।"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रिम गरिरहेका बेला picture-in-picture मोड प्रयोग गर्न मिल्दैन"</string> <string name="system_locale_title" msgid="711882686834677268">"सिस्टम डिफल्ट"</string> <string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"स्मार्टवाचहरू व्यवस्थापन गर्ने सहयोगी वाच प्रोफाइलसम्बन्धी अनुमति"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index a9d654f3a388..6ab375015fe0 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan geen toegang tot de camera van de telefoon krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan geen toegang tot de camera van de tablet krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Je hebt hier geen toegang toe tijdens streaming. Probeer het in plaats daarvan op je telefoon."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan scherm-in-scherm niet bekijken tijdens het streamen"</string> <string name="system_locale_title" msgid="711882686834677268">"Systeemstandaard"</string> <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Smartwatchprofiel voor bijbehorende app om smartwatches te beheren"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 6215213b3637..2dfe51720c6e 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରୁ ଫୋନର କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରୁ ଟାବଲେଟର କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ଷ୍ଟ୍ରିମ କରିବା ସମୟରେ ଏହାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ଷ୍ଟ୍ରିମ କରିବା ସମୟରେ ପିକଚର-ଇନ-ପିକଚର ଦେଖାଯାଇପାରିବ ନାହିଁ"</string> <string name="system_locale_title" msgid="711882686834677268">"ସିଷ୍ଟମ ଡିଫଲ୍ଟ"</string> <string name="default_card_name" msgid="9198284935962911468">"କାର୍ଡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ୱାଚଗୁଡ଼ିକୁ ପରିଚାଳନା କରିବା ପାଇଁ ସହଯୋଗୀ ୱାଚ ପ୍ରୋଫାଇଲ ଅନୁମତି"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index dc53918fca34..2d16afc93117 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਫ਼ੋਨ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਟੈਬਲੈੱਟ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ ਨਹੀਂ ਦੇਖੀ ਜਾ ਸਕਦੀ"</string> <string name="system_locale_title" msgid="711882686834677268">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string> <string name="default_card_name" msgid="9198284935962911468">"ਕਾਰਡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ਘੜੀਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਸੰਬੰਧੀ ਘੜੀ ਪ੍ਰੋਫਾਈਲ ਇਜਾਜ਼ਤ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 4e3fe0d5fcd7..52869c4c6a0c 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nie można korzystać z aparatu telefonu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nie można korzystać z aparatu tabletu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Nie można z tego skorzystać podczas strumieniowania. Użyj telefonu."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Podczas strumieniowania nie można wyświetlać obrazu w obrazie"</string> <string name="system_locale_title" msgid="711882686834677268">"Ustawienie domyślne systemu"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Uprawnienie profilu zegarka towarzyszącego do zarządzania zegarkami"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 47115ba69072..ccd10c4f844a 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível acessar a câmera do smartphone pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível acessar a câmera do tablet pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Não é possível acessar esse conteúdo durante o streaming. Tente pelo smartphone."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível usar o modo picture-in-picture durante o streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"Padrão do sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"CHIP <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permissão do perfil do relógio complementar para gerenciar relógios"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 86e84ba46339..7335d2b6270f 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível aceder à câmara do telemóvel a partir do dispositivo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível aceder à câmara do tablet a partir do dispositivo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Não é possível aceder a isto durante o streaming. Em alternativa, experimente no telemóvel."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível ver o ecrã no ecrã durante o streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"Predefinição do sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"CARTÃO <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorização do perfil de relógio associado para gerir relógios"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 47115ba69072..ccd10c4f844a 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível acessar a câmera do smartphone pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível acessar a câmera do tablet pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Não é possível acessar esse conteúdo durante o streaming. Tente pelo smartphone."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível usar o modo picture-in-picture durante o streaming"</string> <string name="system_locale_title" msgid="711882686834677268">"Padrão do sistema"</string> <string name="default_card_name" msgid="9198284935962911468">"CHIP <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permissão do perfil do relógio complementar para gerenciar relógios"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 14b5b14958d7..e31d465c8bd2 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nu se poate accesa camera foto a telefonului de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nu se poate accesa camera foto a tabletei de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Nu se poate accesa în timpul streamingului. Încearcă pe telefon."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Nu se poate viziona picture-in-picture în timpul streamingului"</string> <string name="system_locale_title" msgid="711882686834677268">"Prestabilită de sistem"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permisiunea pentru gestionarea ceasurilor din profilul ceasului însoțitor"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index da1f520211fd..9ad5dd48d84d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"У устройства <xliff:g id="DEVICE">%1$s</xliff:g> нет доступа к камере телефона."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере планшета."</string> <string name="vdm_secure_window" msgid="161700398158812314">"Этот контент недоступен во время трансляции. Используйте телефон."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Нельзя запустить режим \"Картинка в картинке\" во время потоковой передачи"</string> <string name="system_locale_title" msgid="711882686834677268">"Системные настройки по умолчанию"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Разрешение для сопутствующего приложения управлять часами"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index c09d7f515b9d..c47634206d72 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් දුරකථනයේ කැමරාවට ප්රවේශ විය නොහැකිය"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් ටැබ්ලටයේ කැමරාවට ප්රවේශ විය නොහැකිය"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ප්රවාහය කරන අතරේ මෙයට ප්රවේශ විය නොහැක. ඒ වෙනුවට ඔබේ දුරකථනයෙහි උත්සාහ කරන්න."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ප්රවාහය අතරේ පින්තූරයේ-පින්තූරය බැලිය නොහැක"</string> <string name="system_locale_title" msgid="711882686834677268">"පද්ධති පෙරනිමිය"</string> <string name="default_card_name" msgid="9198284935962911468">"කාඩ්පත <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ඔරලෝසු කළමනාකරණය කිරීමට සහායක ඔරලෝසු පැතිකඩ අවසරය"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 50e519d12446..16fa3ccd723f 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere telefónu"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere tabletu"</string> <string name="vdm_secure_window" msgid="161700398158812314">"K tomuto obsahu nie je počas streamovania prístup. Skúste použiť telefón."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Počas streamingu sa obraz v obraze nedá zobraziť"</string> <string name="system_locale_title" msgid="711882686834677268">"Predvolené systémom"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Povolenie profilu hodiniek pre sprievodnú aplikáciu umožňujúce spravovať hodinky"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 9a57ccf49f36..bc6af03a0fcb 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ni mogoče dostopati do fotoaparata telefona prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ni mogoče dostopati do fotoaparata tabličnega računalnika prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string> <string name="vdm_secure_window" msgid="161700398158812314">"Do te vsebine ni mogoče dostopati med pretočnim predvajanjem. Poskusite s telefonom."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Slike v sliki ni mogoče prikazati med pretočnim predvajanjem."</string> <string name="system_locale_title" msgid="711882686834677268">"Sistemsko privzeto"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Dovoljenje za upravljanje ur v profilu ure v spremljevalni aplikaciji"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index ac6668d91d9c..5ce4aa99e31c 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nuk mund të qasesh në kamerën e telefonit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nuk mund të qasesh në kamerën e tabletit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Nuk mund të kesh qasje në të gjatë transmetimit. Provoje në telefon më mirë."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Figura brenda figurës nuk mund të shikohet gjatë transmetimit"</string> <string name="system_locale_title" msgid="711882686834677268">"Parazgjedhja e sistemit"</string> <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Leje për profilin e \"Orës shoqëruese\" për të menaxhuar orët"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 2b6f90034d2d..84713fdb684b 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -2312,6 +2312,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се приступи камери телефона са <xliff:g id="DEVICE">%1$s</xliff:g> уређаја"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се приступи камери таблета са <xliff:g id="DEVICE">%1$s</xliff:g> уређаја"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Овом не можете да приступате током стримовања. Пробајте на телефону."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Не можете да гледате слику у слици при стримовању"</string> <string name="system_locale_title" msgid="711882686834677268">"Подразумевани системски"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТИЦА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дозвола за профил пратећег сата за управљање сатовима"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 37015712637c..99dc2dad6d2a 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Telefonens kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Surfplattans kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Det går inte att komma åt innehållet när du streamar. Testa med telefonen i stället."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Det går inte att visa bild-i-bild när du streamar"</string> <string name="system_locale_title" msgid="711882686834677268">"Systemets standardinställning"</string> <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Behörighet för den tillhörande klockprofilen att hantera klockor"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 5d948be5d1fc..aeb0d2ba434d 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Huwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Haiwezi kufikia kamera ya kompyuta kibao kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Huwezi kufikia maudhui haya unapotiririsha. Badala yake jaribu kwenye simu yako."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Huwezi kuona picha iliyopachikwa ndani ya picha nyingine unapotiririsha"</string> <string name="system_locale_title" msgid="711882686834677268">"Chaguomsingi la mfumo"</string> <string name="default_card_name" msgid="9198284935962911468">"SIM KADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Ruhusa ya wasifu oanifu wa Saa ili kudhibiti saa"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 702fb851e214..f0e90eaa14a8 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்திலிருந்து மொபைலின் கேமராவை அணுக முடியாது"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்திலிருந்து டேப்லெட்டின் கேமராவை அணுக முடியாது"</string> <string name="vdm_secure_window" msgid="161700398158812314">"ஸ்ட்ரீமின்போது இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பார்க்கவும்."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ஸ்ட்ரீம் செய்யும்போது பிக்ச்சர்-இன்-பிக்ச்சர் அம்சத்தைப் பயன்படுத்த முடியாது"</string> <string name="system_locale_title" msgid="711882686834677268">"சிஸ்டத்தின் இயல்பு"</string> <string name="default_card_name" msgid="9198284935962911468">"கார்டு <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"வாட்ச்சுகளை நிர்வகிக்க, துணைத் தயாரிப்பு ஆப்ஸில் வாட்ச் சுயவிவரத்தை அனுமதித்தல்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 63a9b217a20d..5a972859a86d 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"మీ <xliff:g id="DEVICE">%1$s</xliff:g> నుండి ఫోన్ కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"మీ <xliff:g id="DEVICE">%1$s</xliff:g> నుండి టాబ్లెట్ కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string> <string name="vdm_secure_window" msgid="161700398158812314">"స్ట్రీమింగ్ చేస్తున్నప్పుడు దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ ఫోన్లో ట్రై చేయండి."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"స్ట్రీమింగ్ చేస్తున్నప్పుడు పిక్చర్-ఇన్-పిక్చర్ చూడలేరు"</string> <string name="system_locale_title" msgid="711882686834677268">"సిస్టమ్ ఆటోమేటిక్ సెట్టింగ్"</string> <string name="default_card_name" msgid="9198284935962911468">"కార్డ్ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"వాచ్లను మేనేజ్ చేయడానికి సహాయక వాచ్ ప్రొఫైల్ అనుమతి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 9398393a9aea..8aab6fa5ed02 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"เข้าถึงกล้องของโทรศัพท์จาก <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"เข้าถึงกล้องของแท็บเล็ตจาก <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้"</string> <string name="vdm_secure_window" msgid="161700398158812314">"เข้าถึงเนื้อหานี้ไม่ได้ขณะที่สตรีมมิง โปรดลองเข้าถึงในโทรศัพท์แทน"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"ดูการแสดงภาพซ้อนภาพขณะสตรีมไม่ได้"</string> <string name="system_locale_title" msgid="711882686834677268">"ค่าเริ่มต้นของระบบ"</string> <string name="default_card_name" msgid="9198284935962911468">"ซิมการ์ด <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"สิทธิ์สำหรับโปรไฟล์ในนาฬิกาที่ใช้ร่วมกันเพื่อจัดการนาฬิกา"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 3b2e78814884..beb0c0d511d1 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Hindi ma-access ang camera ng telepono mula sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Hindi ma-access ang camera ng tablet mula sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Hindi ito puwedeng i-access habang nagsi-stream. Subukan na lang sa iyong telepono."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Hindi matingnan nang picture-in-picture habang nagsi-stream"</string> <string name="system_locale_title" msgid="711882686834677268">"Default ng system"</string> <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Pahintulot sa profile ng Relo ng kasamang app na pamahalaan ang mga relo"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 22899c740894..c002f0f4d87e 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına erişilemiyor"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan tabletin kamerasına erişilemiyor"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Canlı oynatılırken bu içeriğe erişilemez. Bunun yerine telefonunuzu kullanmayı deneyin."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Yayın sırasında pencere içinde pencere görüntülenemez"</string> <string name="system_locale_title" msgid="711882686834677268">"Sistem varsayılanı"</string> <string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kol saatlerinin yönetimi için Tamamlayıcı Kol Saati Profili İzni"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index e7b1d66b5e82..d782f2d50e9f 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -2313,6 +2313,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не вдається отримати доступ до камери телефона з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не вдається отримати доступ до камери планшета з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Цей контент недоступний під час потокового передавання. Спробуйте натомість скористатися телефоном."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ви не можете переглядати картинку в картинці під час трансляції"</string> <string name="system_locale_title" msgid="711882686834677268">"Налаштування системи за умовчанням"</string> <string name="default_card_name" msgid="9198284935962911468">"КАРТКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дозвіл профілю годинника для супутнього додатка на керування годинниками"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 95122e9f3586..91b3e95b17a5 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> سے فون کے کیمرا تک رسائی حاصل نہیں کی جا سکتی"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> سے ٹیبلیٹ کے کیمرا تک رسائی حاصل نہیں کی جا سکتی"</string> <string name="vdm_secure_window" msgid="161700398158812314">"سلسلہ بندی کے دوران اس تک رسائی حاصل نہیں کی جا سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"سلسلہ بندی کے دوران تصویر میں تصویر نہیں دیکھ سکتے"</string> <string name="system_locale_title" msgid="711882686834677268">"سسٹم ڈیفالٹ"</string> <string name="default_card_name" msgid="9198284935962911468">"کارڈ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"گھڑیوں کا نظم کرنے کے لیے ساتھی ایپ کی گھڑی کی پروفائل کی اجازت"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 1080918b045b..284abb2a611f 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> qurilmasidan telefonning kamerasiga kirish imkonsiz"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> qurilmasidan planshetning kamerasiga kirish imkonsiz"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Bu kontent striming vaqtida ochilmaydi. Telefon orqali urininb koʻring."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Striming vaqtida tasvir ustida tasvir rejimida koʻrib boʻlmaydi"</string> <string name="system_locale_title" msgid="711882686834677268">"Tizim standarti"</string> <string name="default_card_name" msgid="9198284935962911468">"SIM KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Soatlarni boshqarish uchun hamroh Soat profiliga ruxsat"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 3101facfe4ba..621eaddbe066 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Không truy cập được vào máy ảnh trên điện thoại từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Không truy cập được vào máy ảnh trên máy tính bảng từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Bạn không thể truy cập vào nội dung này trong khi phát trực tuyến. Hãy thử trên điện thoại."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Không thể xem video ở chế độ hình trong hình khi đang truyền trực tuyến"</string> <string name="system_locale_title" msgid="711882686834677268">"Theo chế độ mặc định của hệ thống"</string> <string name="default_card_name" msgid="9198284935962911468">"THẺ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Quyền sử dụng hồ sơ Đồng hồ của ứng dụng đồng hành để quản lý các đồng hồ"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 54221e4da2f1..5152c374d9f8 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问手机的摄像头"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问平板电脑的摄像头"</string> <string name="vdm_secure_window" msgid="161700398158812314">"流式传输时无法访问此内容。您可以尝试在手机上访问。"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"在线播放时无法查看画中画"</string> <string name="system_locale_title" msgid="711882686834677268">"系统默认设置"</string> <string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"用于管理手表的配套手表个人资料权限"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 7e1089375d9e..e7f24ada474d 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取手機的相機"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取平板電腦的相機"</string> <string name="vdm_secure_window" msgid="161700398158812314">"串流播放時無法使用,請改用手機。"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"串流期間無法查看畫中畫"</string> <string name="system_locale_title" msgid="711882686834677268">"系統預設"</string> <string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"用於管理手錶的隨附手錶設定檔權限"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 5f6bc2074bd4..9e0e3a2ea24d 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1941,7 +1941,7 @@ <string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string> <string name="search_language_hint" msgid="7004225294308793583">"請輸入語言名稱"</string> <string name="language_picker_section_suggested" msgid="6556199184638990447">"建議語言"</string> - <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建議的語言"</string> + <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建議地區"</string> <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"建議語言"</string> <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"建議地區"</string> <string name="language_picker_section_all" msgid="1985809075777564284">"所有語言"</string> @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取手機的相機"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取平板電腦的相機"</string> <string name="vdm_secure_window" msgid="161700398158812314">"串流播放時無法存取這項內容,請改用手機。"</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"串流播放時無法查看子母畫面"</string> <string name="system_locale_title" msgid="711882686834677268">"系統預設"</string> <string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"用於管理智慧手錶的配對智慧手錶設定檔權限"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 43c0ada224db..7f8502081ab0 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2311,6 +2311,7 @@ <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ayikwazi ukufinyelela ikhamera yefoni kusuka ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string> <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ayikwazi ukufinyelela ikhamera yethebulethi kusuka ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string> <string name="vdm_secure_window" msgid="161700398158812314">"Lokhu akukwazi ukufinyelelwa ngenkathi usakaza. Zama efonini yakho kunalokho."</string> + <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ayikwazi ukubuka isithombe esiphakathi kwesithombe ngenkathi isakaza"</string> <string name="system_locale_title" msgid="711882686834677268">"Okuzenzakalelayo kwesistimu"</string> <string name="default_card_name" msgid="9198284935962911468">"IKHADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Imvume yephrofayela ye-Companion Watch yokuphatha amawashi"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2d8bfbb8517d..66ff01e6e7b9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5236,7 +5236,7 @@ </string-array> <!-- The integer index of the selected option in config_udfps_touch_detection_options --> - <integer name="config_selected_udfps_touch_detection">3</integer> + <integer name="config_selected_udfps_touch_detection">0</integer> <!-- An array of arrays of side fingerprint sensor properties relative to each display. Note: this value is temporary and is expected to be queried directly diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 08c40ba0e823..b7a5bc826641 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -151,6 +151,23 @@ <integer name="config_timeout_to_receive_delivered_ack_millis">300000</integer> <java-symbol type="integer" name="config_timeout_to_receive_delivered_ack_millis" /> + <!-- Telephony config for services supported by satellite providers. The format of each config + string in the array is as follows: "PLMN_1:service_1,service_2,..." + where PLMN is the satellite PLMN of a provider and service is an integer with the + following value: + 1 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VOICE} + 2 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_DATA} + 3 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_SMS} + 4 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VIDEO} + 5 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_EMERGENCY} + Example of a config string: "10011:2,3" + + The PLMNs not configured in this array will be ignored and will not be used for satellite + scanning. --> + <string-array name="config_satellite_services_supported_by_providers" translatable="false"> + </string-array> + <java-symbol type="array" name="config_satellite_services_supported_by_providers" /> + <!-- Whether enhanced IWLAN handover check is enabled. If enabled, telephony frameworks will not perform handover if the target transport is out of service, or VoPS not supported. The network will be torn down on the source transport, and will be diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f795bd7cc3fd..c120af347741 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1780,6 +1780,10 @@ <string name="biometric_dialog_default_title">Verify it\u2019s you</string> <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] --> <string name="biometric_dialog_default_subtitle">Use your biometric to continue</string> + <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with fingerprint. [CHAR LIMIT=70] --> + <string name="biometric_dialog_fingerprint_subtitle">Use your fingerprint to continue</string> + <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with face. [CHAR LIMIT=70] --> + <string name="biometric_dialog_face_subtitle">Use your face to continue</string> <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] --> <string name="biometric_or_screen_lock_dialog_default_subtitle">Use your biometric or screen lock to continue</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 59306a3a61ce..bffcf5f27ade 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2571,6 +2571,8 @@ <java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" /> <java-symbol type="string" name="biometric_dialog_default_title" /> <java-symbol type="string" name="biometric_dialog_default_subtitle" /> + <java-symbol type="string" name="biometric_dialog_face_subtitle" /> + <java-symbol type="string" name="biometric_dialog_fingerprint_subtitle" /> <java-symbol type="string" name="biometric_or_screen_lock_dialog_default_subtitle" /> <java-symbol type="string" name="biometric_error_hw_unavailable" /> <java-symbol type="string" name="biometric_error_user_canceled" /> diff --git a/core/tests/coretests/src/android/content/TEST_MAPPING b/core/tests/coretests/src/android/content/TEST_MAPPING new file mode 100644 index 000000000000..bbc2458f5d8b --- /dev/null +++ b/core/tests/coretests/src/android/content/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.content.ContentCaptureOptionsTest" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +} diff --git a/core/tests/coretests/src/android/view/contentcapture/TEST_MAPPING b/core/tests/coretests/src/android/view/contentcapture/TEST_MAPPING new file mode 100644 index 000000000000..f8beac2814db --- /dev/null +++ b/core/tests/coretests/src/android/view/contentcapture/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.contentcapture" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +} diff --git a/core/tests/coretests/src/android/view/contentprotection/TEST_MAPPING b/core/tests/coretests/src/android/view/contentprotection/TEST_MAPPING new file mode 100644 index 000000000000..3cd4e17d820b --- /dev/null +++ b/core/tests/coretests/src/android/view/contentprotection/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.contentprotection" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +} diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 2c85fe4e9206..c4530f64a82d 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -346,4 +346,8 @@ <!-- Allow IMS service entitlement app to schedule jobs to run when app in background. --> <allow-in-power-save-except-idle package="com.android.imsserviceentitlement" /> + + <!-- Allow device lock controller app to schedule jobs and alarms when app in background, + otherwise, it may not be able to enforce provision for managed devices. --> + <allow-in-power-save package="com.android.devicelockcontroller" /> </permissions> 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 6d14440c9b18..f8d7b6bc3aad 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 @@ -202,17 +202,18 @@ class DesktopTasksController( } /** - * Moves a single task to freeform and sets the taskBounds to the passed in bounds, - * startBounds + * The first part of the animated move to desktop transition. Applies the changes to move task + * to desktop mode and sets the taskBounds to the passed in bounds, startBounds. This is + * followed with a call to {@link finishMoveToDesktop} or {@link cancelMoveToDesktop}. */ - fun moveToFreeform( + fun startMoveToDesktop( taskInfo: RunningTaskInfo, startBounds: Rect, dragToDesktopValueAnimator: MoveToDesktopAnimator ) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveToFreeform with bounds taskId=%d", + "DesktopTasksController: startMoveToDesktop taskId=%d", taskInfo.taskId ) val wct = WindowContainerTransaction() @@ -221,18 +222,21 @@ class DesktopTasksController( wct.setBounds(taskInfo.token, startBounds) if (Transitions.ENABLE_SHELL_TRANSITIONS) { - enterDesktopTaskTransitionHandler.startMoveToFreeformAnimation(wct, - dragToDesktopValueAnimator, mOnAnimationFinishedCallback) + enterDesktopTaskTransitionHandler.startMoveToDesktop(wct, dragToDesktopValueAnimator, + mOnAnimationFinishedCallback) } else { shellTaskOrganizer.applyTransaction(wct) } } - /** Brings apps to front and sets freeform task bounds */ - private fun moveToDesktopWithAnimation(taskInfo: RunningTaskInfo, freeformBounds: Rect) { + /** + * The second part of the animated move to desktop transition, called after + * {@link startMoveToDesktop}. Brings apps to front and sets freeform task bounds. + */ + private fun finalizeMoveToDesktop(taskInfo: RunningTaskInfo, freeformBounds: Rect) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveToDesktop with animation taskId=%d", + "DesktopTasksController: finalizeMoveToDesktop taskId=%d", taskInfo.taskId ) val wct = WindowContainerTransaction() @@ -241,8 +245,8 @@ class DesktopTasksController( wct.setBounds(taskInfo.token, freeformBounds) if (Transitions.ENABLE_SHELL_TRANSITIONS) { - enterDesktopTaskTransitionHandler.startTransition( - Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct, mOnAnimationFinishedCallback) + enterDesktopTaskTransitionHandler.finalizeMoveToDesktop(wct, + mOnAnimationFinishedCallback) } else { shellTaskOrganizer.applyTransaction(wct) releaseVisualIndicator() @@ -272,13 +276,14 @@ class DesktopTasksController( } /** - * Move a task to fullscreen after being dragged from fullscreen and released back into - * status bar area + * The second part of the animated move to desktop transition, called after + * {@link startMoveToDesktop}. Move a task to fullscreen after being dragged from fullscreen + * and released back into status bar area. */ - fun cancelMoveToFreeform(task: RunningTaskInfo, moveToDesktopAnimator: MoveToDesktopAnimator) { + fun cancelMoveToDesktop(task: RunningTaskInfo, moveToDesktopAnimator: MoveToDesktopAnimator) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: cancelMoveToFreeform taskId=%d", + "DesktopTasksController: cancelMoveToDesktop taskId=%d", task.taskId ) val wct = WindowContainerTransaction() @@ -784,7 +789,7 @@ class DesktopTasksController( taskInfo: RunningTaskInfo, freeformBounds: Rect ) { - moveToDesktopWithAnimation(taskInfo, freeformBounds) + finalizeMoveToDesktop(taskInfo, freeformBounds) } private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java index 650cac5cb999..1acf783257f2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java @@ -79,7 +79,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition * @param wct WindowContainerTransaction for transition * @param onAnimationEndCallback to be called after animation */ - public void startTransition(@WindowManager.TransitionType int type, + private void startTransition(@WindowManager.TransitionType int type, @NonNull WindowContainerTransaction wct, Consumer<SurfaceControl.Transaction> onAnimationEndCallback) { mOnAnimationFinishedCallback = onAnimationEndCallback; @@ -88,17 +88,29 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition } /** - * Starts Transition of type TRANSIT_ENTER_FREEFORM + * Starts Transition of type TRANSIT_START_MOVE_TO_DESKTOP_MODE * @param wct WindowContainerTransaction for transition * @param moveToDesktopAnimator Animator that shrinks and positions task during two part move * to desktop animation * @param onAnimationEndCallback to be called after animation */ - public void startMoveToFreeformAnimation(@NonNull WindowContainerTransaction wct, + public void startMoveToDesktop(@NonNull WindowContainerTransaction wct, @NonNull MoveToDesktopAnimator moveToDesktopAnimator, Consumer<SurfaceControl.Transaction> onAnimationEndCallback) { mMoveToDesktopAnimator = moveToDesktopAnimator; - startTransition(Transitions.TRANSIT_ENTER_FREEFORM, wct, onAnimationEndCallback); + startTransition(Transitions.TRANSIT_START_MOVE_TO_DESKTOP_MODE, wct, + onAnimationEndCallback); + } + + /** + * Starts Transition of type TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE + * @param wct WindowContainerTransaction for transition + * @param onAnimationEndCallback to be called after animation + */ + public void finalizeMoveToDesktop(@NonNull WindowContainerTransaction wct, + Consumer<SurfaceControl.Transaction> onAnimationEndCallback) { + startTransition(Transitions.TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE, wct, + onAnimationEndCallback); } /** @@ -155,7 +167,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition } final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); - if (type == Transitions.TRANSIT_ENTER_FREEFORM + if (type == Transitions.TRANSIT_START_MOVE_TO_DESKTOP_MODE && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { // Transitioning to freeform but keeping fullscreen bounds, so the crop is set // to null and we don't require an animation @@ -182,7 +194,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition } Rect endBounds = change.getEndAbsBounds(); - if (type == Transitions.TRANSIT_ENTER_DESKTOP_MODE + if (type == Transitions.TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM && !endBounds.isEmpty()) { // This Transition animates a task to freeform bounds after being dragged into freeform diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index af8ef174b168..7699b4bfd13a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -737,12 +737,23 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, Intent fillInIntent2 = null; final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent1); final String packageName2 = SplitScreenUtils.getPackageName(pendingIntent2); + final ActivityOptions activityOptions1 = options1 != null + ? ActivityOptions.fromBundle(options1) : ActivityOptions.makeBasic(); + final ActivityOptions activityOptions2 = options2 != null + ? ActivityOptions.fromBundle(options2) : ActivityOptions.makeBasic(); if (samePackage(packageName1, packageName2, userId1, userId2)) { if (supportMultiInstancesSplit(packageName1)) { fillInIntent1 = new Intent(); fillInIntent1.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); fillInIntent2 = new Intent(); fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + + if (shortcutInfo1 != null) { + activityOptions1.setApplyMultipleTaskFlagForShortcut(true); + } + if (shortcutInfo2 != null) { + activityOptions2.setApplyMultipleTaskFlagForShortcut(true); + } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); } else { pendingIntent2 = null; @@ -754,9 +765,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, Toast.LENGTH_SHORT).show(); } } - mStageCoordinator.startIntents(pendingIntent1, fillInIntent1, shortcutInfo1, options1, - pendingIntent2, fillInIntent2, shortcutInfo2, options2, splitPosition, splitRatio, - remoteTransition, instanceId); + mStageCoordinator.startIntents(pendingIntent1, fillInIntent1, shortcutInfo1, + activityOptions1.toBundle(), pendingIntent2, fillInIntent2, shortcutInfo2, + activityOptions2.toBundle(), splitPosition, splitRatio, remoteTransition, + instanceId); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index e52fd00e7df7..dc78c9b139f9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -407,7 +407,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { change.getEndAbsBounds().width(), change.getEndAbsBounds().height()); } // Rotation change of independent non display window container. - if (change.getParent() == null + if (change.getParent() == null && !change.hasFlags(FLAG_IS_DISPLAY) && change.getStartRotation() != change.getEndRotation()) { startRotationAnimation(startTransaction, change, info, ROTATION_ANIMATION_ROTATE, animations, onAnimFinish); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java index a242c72db8b3..c22cc6fbea8f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java @@ -186,9 +186,12 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler { @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, @NonNull Transitions.TransitionFinishCallback finishCallback) { final RemoteTransition remoteTransition = mRequestedRemotes.get(mergeTarget); - final IRemoteTransition remote = remoteTransition.getRemoteTransition(); + if (remoteTransition == null) return; + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Merge into remote: %s", remoteTransition); + + final IRemoteTransition remote = remoteTransition.getRemoteTransition(); if (remote == null) return; IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 75659960bc32..4ca383f66267 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -149,11 +149,13 @@ public class Transitions implements RemoteCallable<Transitions>, /** Transition type for maximize to freeform transition. */ public static final int TRANSIT_RESTORE_FROM_MAXIMIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 9; - /** Transition type to freeform in desktop mode. */ - public static final int TRANSIT_ENTER_FREEFORM = WindowManager.TRANSIT_FIRST_CUSTOM + 10; + /** Transition type for starting the move to desktop mode. */ + public static final int TRANSIT_START_MOVE_TO_DESKTOP_MODE = + WindowManager.TRANSIT_FIRST_CUSTOM + 10; - /** Transition type to freeform in desktop mode. */ - public static final int TRANSIT_ENTER_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 11; + /** Transition type for finalizing the move to desktop mode. */ + public static final int TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE = + WindowManager.TRANSIT_FIRST_CUSTOM + 11; /** Transition type to fullscreen from desktop mode. */ public static final int TRANSIT_EXIT_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 12; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 1a18fc2d7546..80cf96a93efa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -197,7 +197,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change) { if (change.getMode() == WindowManager.TRANSIT_CHANGE - && (info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE + && (info.getType() == Transitions.TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE || info.getType() == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE || info.getType() == Transitions.TRANSIT_EXIT_DESKTOP_MODE || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE)) { @@ -616,7 +616,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } else if (mMoveToDesktopAnimator != null) { relevantDecor.incrementRelayoutBlock(); mDesktopTasksController.ifPresent( - c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo, + c -> c.cancelMoveToDesktop(relevantDecor.mTaskInfo, mMoveToDesktopAnimator)); mMoveToDesktopAnimator = null; return; @@ -643,7 +643,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDragToDesktopAnimationStartBounds, relevantDecor.mTaskInfo, relevantDecor.mTaskSurface); mDesktopTasksController.ifPresent( - c -> c.moveToFreeform(relevantDecor.mTaskInfo, + c -> c.startMoveToDesktop(relevantDecor.mTaskInfo, mDragToDesktopAnimationStartBounds, mMoveToDesktopAnimator)); mMoveToDesktopAnimator.startAnimation(); diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt index fd56a6e49d3e..8a3c2c975faa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/SplitScreenUtils.kt @@ -42,7 +42,7 @@ import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary import org.junit.Assert.assertNotNull -internal object SplitScreenUtils { +object SplitScreenUtils { private const val TIMEOUT_MS = 3_000L private const val DRAG_DURATION_MS = 1_000L private const val NOTIFICATION_SCROLLER = "notification_stack_scroller" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt index 0f9579d58929..69c8ecd5644d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt @@ -17,7 +17,6 @@ package com.android.wm.shell.flicker.appcompat import android.content.Context -import android.system.helpers.CommandsHelper import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTestData @@ -29,15 +28,18 @@ import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd import com.android.wm.shell.flicker.appWindowIsVisibleAtStart import com.android.wm.shell.flicker.appWindowKeepVisible import com.android.wm.shell.flicker.layerKeepVisible -import org.junit.After + import org.junit.Assume import org.junit.Before +import org.junit.Rule abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) { protected val context: Context = instrumentation.context protected val letterboxApp = LetterboxAppHelper(instrumentation) - lateinit var cmdHelper: CommandsHelper - private lateinit var letterboxStyle: HashMap<String, String> + + @JvmField + @Rule + val letterboxRule: LetterboxRule = LetterboxRule() /** {@inheritDoc} */ override val transition: FlickerBuilder.() -> Unit @@ -52,50 +54,7 @@ abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) { @Before fun before() { - cmdHelper = CommandsHelper.getInstance(instrumentation) - Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest()) - letterboxStyle = mapLetterboxStyle() - resetLetterboxStyle() - setLetterboxEducationEnabled(false) - } - - @After - fun after() { - resetLetterboxStyle() - } - - private fun mapLetterboxStyle(): HashMap<String, String> { - val res = cmdHelper.executeShellCommand("wm get-letterbox-style") - val lines = res.lines() - val map = HashMap<String, String>() - for (line in lines) { - val keyValuePair = line.split(":") - if (keyValuePair.size == 2) { - val key = keyValuePair[0].trim() - map[key] = keyValuePair[1].trim() - } - } - return map - } - - private fun getLetterboxStyle(): HashMap<String, String> { - if (!::letterboxStyle.isInitialized) { - letterboxStyle = mapLetterboxStyle() - } - return letterboxStyle - } - - private fun resetLetterboxStyle() { - cmdHelper.executeShellCommand("wm reset-letterbox-style") - } - - private fun setLetterboxEducationEnabled(enabled: Boolean) { - cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled") - } - - private fun isIgnoreOrientationRequest(): Boolean { - val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request") - return res != null && res.contains("true") + Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest) } fun FlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation) @@ -115,7 +74,7 @@ abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) { /** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */ private fun assumeLetterboxRoundedCornersEnabled() { - Assume.assumeTrue(getLetterboxStyle().getValue("Corner radius") != "0") + Assume.assumeTrue(letterboxRule.hasCornerRadius) } fun assertLetterboxAppVisibleAtStartAndEnd() { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt new file mode 100644 index 000000000000..5a1136f97c6f --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/LetterboxRule.kt @@ -0,0 +1,108 @@ +/* + * 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.wm.shell.flicker.appcompat + +import android.app.Instrumentation +import android.system.helpers.CommandsHelper +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +/** + * JUnit Rule to handle letterboxStyles and states + */ +class LetterboxRule( + private val withLetterboxEducationEnabled: Boolean = false, + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(), + private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation) +) : TestRule { + + private val execAdb: (String) -> String = {cmd -> cmdHelper.executeShellCommand(cmd)} + private lateinit var _letterboxStyle: MutableMap<String, String> + + val letterboxStyle: Map<String, String> + get() { + if (!::_letterboxStyle.isInitialized) { + _letterboxStyle = mapLetterboxStyle() + } + return _letterboxStyle + } + + val cornerRadius: Int? + get() = asInt(letterboxStyle["Corner radius"]) + + val hasCornerRadius: Boolean + get() { + val radius = cornerRadius + return radius != null && radius > 0 + } + + val isIgnoreOrientationRequest: Boolean + get() = execAdb("wm get-ignore-orientation-request")?.contains("true") ?: false + + override fun apply(base: Statement?, description: Description?): Statement { + resetLetterboxStyle() + _letterboxStyle = mapLetterboxStyle() + val isLetterboxEducationEnabled = _letterboxStyle.getValue("Is education enabled") + var hasLetterboxEducationStateChanged = false + if ("$withLetterboxEducationEnabled" != isLetterboxEducationEnabled) { + hasLetterboxEducationStateChanged = true + execAdb("wm set-letterbox-style --isEducationEnabled " + + withLetterboxEducationEnabled) + } + return try { + object : Statement() { + @Throws(Throwable::class) + override fun evaluate() { + base!!.evaluate() + } + } + } finally { + if (hasLetterboxEducationStateChanged) { + execAdb("wm set-letterbox-style --isEducationEnabled " + + isLetterboxEducationEnabled + ) + } + resetLetterboxStyle() + } + } + + private fun mapLetterboxStyle(): HashMap<String, String> { + val res = execAdb("wm get-letterbox-style") + val lines = res.lines() + val map = HashMap<String, String>() + for (line in lines) { + val keyValuePair = line.split(":") + if (keyValuePair.size == 2) { + val key = keyValuePair[0].trim() + map[key] = keyValuePair[1].trim() + } + } + return map + } + + private fun resetLetterboxStyle() { + execAdb("wm reset-letterbox-style") + } + + private fun asInt(str: String?): Int? = try { + str?.toInt() + } catch (e: NumberFormatException) { + null + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt index a7bd2584ba23..67d5718e6c1f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt @@ -31,7 +31,7 @@ import org.junit.runners.Parameterized /** * Test launching app in size compat mode. * - * To run this test: `atest WMShellFlickerTests:OpenAppInSizeCompatModeTest` + * To run this test: `atest WMShellFlickerTestsOther:OpenAppInSizeCompatModeTest` * * Actions: * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt new file mode 100644 index 000000000000..e6ca261a317f --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt @@ -0,0 +1,128 @@ +/* + * 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.wm.shell.flicker.appcompat + +import android.platform.test.annotations.Postsubmit +import android.tools.common.Rotation +import android.tools.common.flicker.assertions.FlickerTest +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import androidx.test.filters.RequiresDevice +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +/** + * Test launching app in size compat mode. + * + * To run this test: `atest WMShellFlickerTestsOther:OpenTransparentActivityTest` + * + * Actions: + * ``` + * Launch a letteboxed app and then a transparent activity from it. We test the bounds + * are the same. + * ``` + * + * Notes: + * ``` + * Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [BaseTest] + * ``` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +class OpenTransparentActivityTest(flicker: LegacyFlickerTest) : TransparentBaseAppCompat(flicker) { + + /** {@inheritDoc} */ + override val transition: FlickerBuilder.() -> Unit + get() = { + setup { + letterboxTranslucentLauncherApp.launchViaIntent(wmHelper) + } + transitions { + waitAndGetLaunchTransparent()?.click() ?: error("Launch Transparent not found") + } + teardown { + letterboxTranslucentApp.exit(wmHelper) + letterboxTranslucentLauncherApp.exit(wmHelper) + } + } + + /** + * Checks the transparent activity is launched on top of the opaque one + */ + @Postsubmit + @Test + fun translucentActivityIsLaunchedOnTopOfOpaqueActivity() { + flicker.assertWm { + this.isAppWindowOnTop(letterboxTranslucentLauncherApp) + .then() + .isAppWindowOnTop(letterboxTranslucentApp) + } + } + + /** + * Checks that the activity is letterboxed + */ + @Postsubmit + @Test + fun translucentActivityIsLetterboxed() { + flicker.assertLayers { isVisible(ComponentNameMatcher.LETTERBOX) } + } + + /** + * Checks that the translucent activity inherits bounds from the opaque one. + */ + @Postsubmit + @Test + fun translucentActivityInheritsBoundsFromOpaqueActivity() { + flicker.assertLayersEnd { + this.visibleRegion(letterboxTranslucentApp) + .coversExactly(visibleRegion(letterboxTranslucentLauncherApp).region) + } + } + + /** + * Checks that the translucent activity has rounded corners + */ + @Postsubmit + @Test + fun translucentActivityHasRoundedCorners() { + flicker.assertLayersEnd { + this.hasRoundedCorners(letterboxTranslucentApp) + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestFactory.rotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTest> { + return LegacyFlickerTestFactory + .nonRotationTests(supportedRotations = listOf(Rotation.ROTATION_90)) + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt index e875aae431a1..68fa8d2fc2e8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt @@ -32,7 +32,9 @@ import org.junit.runners.Parameterized /** * Test launching a fixed portrait letterboxed app in landscape and repositioning to the right. * - * To run this test: `atest WMShellFlickerTests:RepositionFixedPortraitAppTest` Actions: + * To run this test: `atest WMShellFlickerTestsOther:RepositionFixedPortraitAppTest` + * + * Actions: * * ``` * Launch a fixed portrait app in landscape to letterbox app diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt index a18a144b4bf1..fcb6931af9a2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt @@ -31,7 +31,7 @@ import org.junit.runners.Parameterized /** * Test restarting app in size compat mode. * - * To run this test: `atest WMShellFlickerTests:RestartAppInSizeCompatModeTest` + * To run this test: `atest WMShellFlickerTestsOther:RestartAppInSizeCompatModeTest` * * Actions: * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt new file mode 100644 index 000000000000..ea0392cee95a --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt @@ -0,0 +1,63 @@ +/* + * 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.wm.shell.flicker.appcompat + +import android.content.Context +import android.tools.device.flicker.legacy.FlickerTestData +import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.device.helpers.FIND_TIMEOUT +import android.tools.device.traces.parsers.toFlickerComponent +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiObject2 +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.helpers.LetterboxAppHelper +import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.flicker.BaseTest +import org.junit.Assume +import org.junit.Before +import org.junit.Rule + +abstract class TransparentBaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) { + protected val context: Context = instrumentation.context + protected val letterboxTranslucentLauncherApp = LetterboxAppHelper( + instrumentation, + launcherName = ActivityOptions.LaunchTransparentActivity.LABEL, + component = ActivityOptions.LaunchTransparentActivity.COMPONENT.toFlickerComponent() + ) + protected val letterboxTranslucentApp = LetterboxAppHelper( + instrumentation, + launcherName = ActivityOptions.TransparentActivity.LABEL, + component = ActivityOptions.TransparentActivity.COMPONENT.toFlickerComponent() + ) + + @JvmField + @Rule + val letterboxRule: LetterboxRule = LetterboxRule() + + @Before + fun before() { + Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest) + } + + protected fun FlickerTestData.waitAndGetLaunchTransparent(): UiObject2? = + device.wait( + Until.findObject(By.text("Launch Transparent")), + FIND_TIMEOUT + ) + + protected fun FlickerTestData.goBack() = device.pressBack() +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java index c6642f3472f0..885ae3851c6d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java @@ -99,16 +99,17 @@ public class EnterDesktopTaskTransitionHandlerTest { final int taskId = 1; WindowContainerTransaction wct = new WindowContainerTransaction(); doReturn(mToken).when(mTransitions) - .startTransition(Transitions.TRANSIT_ENTER_FREEFORM, wct, + .startTransition(Transitions.TRANSIT_START_MOVE_TO_DESKTOP_MODE, wct, mEnterDesktopTaskTransitionHandler); doReturn(taskId).when(mMoveToDesktopAnimator).getTaskId(); - mEnterDesktopTaskTransitionHandler.startMoveToFreeformAnimation(wct, + mEnterDesktopTaskTransitionHandler.startMoveToDesktop(wct, mMoveToDesktopAnimator, null); TransitionInfo.Change change = createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM); - TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_ENTER_FREEFORM, change); + TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_START_MOVE_TO_DESKTOP_MODE, + change); assertTrue(mEnterDesktopTaskTransitionHandler @@ -120,17 +121,18 @@ public class EnterDesktopTaskTransitionHandlerTest { @Test public void testTransitEnterDesktopModeAnimation() throws Throwable { - final int transitionType = Transitions.TRANSIT_ENTER_DESKTOP_MODE; + final int transitionType = Transitions.TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE; final int taskId = 1; WindowContainerTransaction wct = new WindowContainerTransaction(); doReturn(mToken).when(mTransitions) .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler); - mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null); + mEnterDesktopTaskTransitionHandler.finalizeMoveToDesktop(wct, null); TransitionInfo.Change change = createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM); change.setEndAbsBounds(new Rect(0, 0, 1, 1)); - TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_ENTER_DESKTOP_MODE, change); + TransitionInfo info = createTransitionInfo( + Transitions.TRANSIT_FINALIZE_MOVE_TO_DESKTOP_MODE, change); runOnUiThread(() -> { try { diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp index f71e7289bd37..b87002371775 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.cpp +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -88,6 +88,9 @@ void ShaderCache::initShaderDiskCache(const void* identity, ssize_t size) { mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename)); validateCache(identity, size); mInitialized = true; + if (identity != nullptr && size > 0 && mIDHash.size()) { + set(&sIDKey, sizeof(sIDKey), mIDHash.data(), mIDHash.size()); + } } } @@ -96,11 +99,6 @@ void ShaderCache::setFilename(const char* filename) { mFilename = filename; } -BlobCache* ShaderCache::getBlobCacheLocked() { - LOG_ALWAYS_FATAL_IF(!mInitialized, "ShaderCache has not been initialized"); - return mBlobCache.get(); -} - sk_sp<SkData> ShaderCache::load(const SkData& key) { ATRACE_NAME("ShaderCache::load"); size_t keySize = key.size(); @@ -115,8 +113,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) { if (!valueBuffer) { return nullptr; } - BlobCache* bc = getBlobCacheLocked(); - size_t valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize); + size_t valueSize = mBlobCache->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize); int maxTries = 3; while (valueSize > mObservedBlobValueSize && maxTries > 0) { mObservedBlobValueSize = std::min(valueSize, maxValueSize); @@ -126,7 +123,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) { return nullptr; } valueBuffer = newValueBuffer; - valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize); + valueSize = mBlobCache->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize); maxTries--; } if (!valueSize) { @@ -143,16 +140,17 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) { return SkData::MakeFromMalloc(valueBuffer, valueSize); } -namespace { -// Helper for BlobCache::set to trace the result. -void set(BlobCache* cache, const void* key, size_t keySize, const void* value, size_t valueSize) { - switch (cache->set(key, keySize, value, valueSize)) { +void ShaderCache::set(const void* key, size_t keySize, const void* value, size_t valueSize) { + switch (mBlobCache->set(key, keySize, value, valueSize)) { case BlobCache::InsertResult::kInserted: // This is what we expect/hope. It means the cache is large enough. return; case BlobCache::InsertResult::kDidClean: { ATRACE_FORMAT("ShaderCache: evicted an entry to fit {key: %lu value %lu}!", keySize, valueSize); + if (mIDHash.size()) { + set(&sIDKey, sizeof(sIDKey), mIDHash.data(), mIDHash.size()); + } return; } case BlobCache::InsertResult::kNotEnoughSpace: { @@ -172,15 +170,10 @@ void set(BlobCache* cache, const void* key, size_t keySize, const void* value, s } } } -} // namespace void ShaderCache::saveToDiskLocked() { ATRACE_NAME("ShaderCache::saveToDiskLocked"); if (mInitialized && mBlobCache) { - if (mIDHash.size()) { - auto key = sIDKey; - set(mBlobCache.get(), &key, sizeof(key), mIDHash.data(), mIDHash.size()); - } // The most straightforward way to make ownership shared mMutex.unlock(); mMutex.lock_shared(); @@ -209,11 +202,10 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& / const void* value = data.data(); - BlobCache* bc = getBlobCacheLocked(); if (mInStoreVkPipelineInProgress) { if (mOldPipelineCacheSize == -1) { // Record the initial pipeline cache size stored in the file. - mOldPipelineCacheSize = bc->get(key.data(), keySize, nullptr, 0); + mOldPipelineCacheSize = mBlobCache->get(key.data(), keySize, nullptr, 0); } if (mNewPipelineCacheSize != -1 && mNewPipelineCacheSize == valueSize) { // There has not been change in pipeline cache size. Stop trying to save. @@ -228,7 +220,7 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& / mNewPipelineCacheSize = -1; mTryToStorePipelineCache = true; } - set(bc, key.data(), keySize, value, valueSize); + set(key.data(), keySize, value, valueSize); if (!mSavePending && mDeferredSaveDelayMs > 0) { mSavePending = true; diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h index 2f91c778b8a0..74955503dbb1 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.h +++ b/libs/hwui/pipeline/skia/ShaderCache.h @@ -96,20 +96,18 @@ private: void operator=(const ShaderCache&) = delete; /** - * "getBlobCacheLocked" returns the BlobCache object being used to store the - * key/value blob pairs. If the BlobCache object has not yet been created, - * this will do so, loading the serialized cache contents from disk if - * possible. - */ - BlobCache* getBlobCacheLocked() REQUIRES(mMutex); - - /** * "validateCache" updates the cache to match the given identity. If the * cache currently has the wrong identity, all entries in the cache are cleared. */ bool validateCache(const void* identity, ssize_t size) REQUIRES(mMutex); /** + * Helper for BlobCache::set to trace the result and ensure the identity hash + * does not get evicted. + */ + void set(const void* key, size_t keySize, const void* value, size_t valueSize) REQUIRES(mMutex); + + /** * "saveToDiskLocked" attempts to save the current contents of the cache to * disk. If the identity hash exists, we will insert the identity hash into * the cache for next validation. @@ -127,11 +125,9 @@ private: bool mInitialized GUARDED_BY(mMutex) = false; /** - * "mBlobCache" is the cache in which the key/value blob pairs are stored. It - * is initially NULL, and will be initialized by getBlobCacheLocked the - * first time it's needed. - * The blob cache contains the Android build number. We treat version mismatches as an empty - * cache (logic implemented in BlobCache::unflatten). + * "mBlobCache" is the cache in which the key/value blob pairs are stored. + * The blob cache contains the Android build number. We treat version mismatches + * as an empty cache (logic implemented in BlobCache::unflatten). */ std::unique_ptr<FileBlobCache> mBlobCache GUARDED_BY(mMutex); diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 31a92ac5ab23..46698a6fdcc0 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -40,7 +40,7 @@ namespace android { namespace uirenderer { namespace renderthread { -static std::array<std::string_view, 19> sEnableExtensions{ +static std::array<std::string_view, 20> sEnableExtensions{ VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, @@ -60,6 +60,7 @@ static std::array<std::string_view, 19> sEnableExtensions{ VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, + VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, }; static bool shouldEnableExtension(const std::string_view& extension) { diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java index 9b33704cc8e7..eccf6047b90c 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java @@ -191,6 +191,8 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED) && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION) + && isPendingIntentValid(intent, + SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED) && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_SUCCESS) && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); @@ -276,6 +278,8 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ case SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED: return "request failed"; case SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION: return "not default data subscription"; + case SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED: + return "notifications disabled"; case SlicePurchaseController.EXTRA_INTENT_SUCCESS: return "success"; case SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN: return "notification shown"; @@ -321,26 +325,45 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ } private void onDisplayPerformanceBoostNotification(@NonNull Context context, - @NonNull Intent intent, boolean repeat) { - if (!repeat && !isIntentValid(intent)) { + @NonNull Intent intent, boolean localeChanged) { + if (!localeChanged && !isIntentValid(intent)) { sendSlicePurchaseAppResponse(intent, SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED); return; } Resources res = getResources(context); - NotificationChannel channel = new NotificationChannel( - PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID, - res.getString(R.string.performance_boost_notification_channel), - NotificationManager.IMPORTANCE_DEFAULT); - // CarrierDefaultApp notifications are unblockable by default. Make this channel blockable - // to allow users to disable notifications posted to this channel without affecting other - // notifications in this application. - channel.setBlockable(true); - context.getSystemService(NotificationManager.class).createNotificationChannel(channel); + NotificationManager notificationManager = + context.getSystemService(NotificationManager.class); + NotificationChannel channel = notificationManager.getNotificationChannel( + PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID); + if (channel == null) { + channel = new NotificationChannel( + PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID, + res.getString(R.string.performance_boost_notification_channel), + NotificationManager.IMPORTANCE_DEFAULT); + // CarrierDefaultApp notifications are unblockable by default. + // Make this channel blockable to allow users to disable notifications posted to this + // channel without affecting other notifications in this application. + channel.setBlockable(true); + context.getSystemService(NotificationManager.class).createNotificationChannel(channel); + } else if (localeChanged) { + // If the channel already exists but the locale has changed, update the channel name. + channel.setName(res.getString(R.string.performance_boost_notification_channel)); + } - String carrier = intent.getStringExtra(SlicePurchaseController.EXTRA_CARRIER); + boolean channelNotificationsDisabled = + channel.getImportance() == NotificationManager.IMPORTANCE_NONE; + if (channelNotificationsDisabled || !notificationManager.areNotificationsEnabled()) { + // If notifications are disabled for the app or channel, fail the purchase request. + logd("Purchase request failed because notifications are disabled for the " + + (channelNotificationsDisabled ? "channel." : "application.")); + sendSlicePurchaseAppResponse(intent, + SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED); + return; + } + String carrier = intent.getStringExtra(SlicePurchaseController.EXTRA_CARRIER); Notification notification = new Notification.Builder(context, PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID) .setContentTitle(res.getString( @@ -369,11 +392,12 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ int capability = intent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY, SlicePurchaseController.PREMIUM_CAPABILITY_INVALID); - logd((repeat ? "Update" : "Display") + " the performance boost notification for capability " + logd((localeChanged ? "Update" : "Display") + + " the performance boost notification for capability " + TelephonyManager.convertPremiumCapabilityToString(capability)); context.getSystemService(NotificationManager.class).notifyAsUser( PERFORMANCE_BOOST_NOTIFICATION_TAG, capability, notification, UserHandle.ALL); - if (!repeat) { + if (!localeChanged) { sIntents.put(capability, intent); sendSlicePurchaseAppResponse(intent, SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java index 61847b517c8d..3c8ef6ed0550 100644 --- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java +++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -72,6 +73,7 @@ public class SlicePurchaseBroadcastReceiverTest { @Mock PendingIntent mContentIntent1; @Mock PendingIntent mContentIntent2; @Mock PendingIntent mNotificationShownIntent; + @Mock PendingIntent mNotificationsDisabledIntent; @Mock Context mContext; @Mock Resources mResources; @Mock Configuration mConfiguration; @@ -90,6 +92,7 @@ public class SlicePurchaseBroadcastReceiverTest { doReturn("").when(mResources).getString(anyInt()); doReturn(mNotificationManager).when(mContext) .getSystemService(eq(NotificationManager.class)); + doReturn(true).when(mNotificationManager).areNotificationsEnabled(); doReturn(mApplicationInfo).when(mContext).getApplicationInfo(); doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mSpiedResources).when(mContext).getResources(); @@ -221,12 +224,10 @@ public class SlicePurchaseBroadcastReceiverTest { doReturn(true).when(mPendingIntent).isBroadcast(); doReturn(mPendingIntent).when(mIntent).getParcelableExtra( anyString(), eq(PendingIntent.class)); - doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mNotificationShownIntent) - .getCreatorPackage(); - doReturn(true).when(mNotificationShownIntent).isBroadcast(); - doReturn(mNotificationShownIntent).when(mIntent).getParcelableExtra( - eq(SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN), - eq(PendingIntent.class)); + createValidPendingIntent(mNotificationShownIntent, + SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); + createValidPendingIntent(mNotificationsDisabledIntent, + SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED); // spy notification intents to prevent PendingIntent issues doReturn(mContentIntent1).when(mSlicePurchaseBroadcastReceiver).createContentIntent( @@ -253,6 +254,12 @@ public class SlicePurchaseBroadcastReceiverTest { mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent); } + private void createValidPendingIntent(@NonNull PendingIntent intent, @NonNull String extra) { + doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(intent).getCreatorPackage(); + doReturn(true).when(intent).isBroadcast(); + doReturn(intent).when(mIntent).getParcelableExtra(eq(extra), eq(PendingIntent.class)); + } + @Test public void testNotificationCanceled() { // send ACTION_NOTIFICATION_CANCELED @@ -335,4 +342,22 @@ public class SlicePurchaseBroadcastReceiverTest { clearInvocations(mConfiguration); return captor.getValue(); } + + @Test + public void testNotificationsDisabled() throws Exception { + doReturn(false).when(mNotificationManager).areNotificationsEnabled(); + + displayPerformanceBoostNotification(); + + // verify notification was not shown + verify(mNotificationManager, never()).notifyAsUser( + eq(SlicePurchaseBroadcastReceiver.PERFORMANCE_BOOST_NOTIFICATION_TAG), + eq(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY), + any(), + eq(UserHandle.ALL)); + verify(mNotificationShownIntent, never()).send(); + + // verify SlicePurchaseController was notified that notifications are disabled + verify(mNotificationsDisabledIntent).send(); + } } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index e1eb36ac276c..25ac3c9d9074 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -419,12 +419,20 @@ public class DynamicSystemInstallationService extends Service mDynSystem.remove(); } + private boolean isDsuSlotLocked() { + // Slot names ending with ".lock" are a customized installation. + // We expect the client app to provide custom UI to enter/exit DSU mode. + // We will ignore the ACTION_REBOOT_TO_NORMAL command and will not show + // notifications in this case. + return mDynSystem.getActiveDsuSlot().endsWith(".lock"); + } + private void executeRebootToNormalCommand() { if (!isInDynamicSystem()) { Log.e(TAG, "It's already running in normal system."); return; } - if (mDynSystem.getActiveDsuSlot().endsWith(".lock")) { + if (isDsuSlotLocked()) { Log.e(TAG, "Ignore the reboot intent for a locked DSU slot"); return; } @@ -449,13 +457,13 @@ public class DynamicSystemInstallationService extends Service private void executeNotifyIfInUseCommand() { switch (getStatus()) { case STATUS_IN_USE: - if (!mHideNotification) { + if (!mHideNotification && !isDsuSlotLocked()) { startForeground(NOTIFICATION_ID, buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED)); } break; case STATUS_READY: - if (!mHideNotification) { + if (!mHideNotification && !isDsuSlotLocked()) { startForeground(NOTIFICATION_ID, buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED)); } diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java index 00dd8cc88da2..1a938d6ec37e 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java @@ -179,7 +179,8 @@ public abstract class Tile implements Parcelable { * Check whether tile has order. */ public boolean hasOrder() { - return mMetaData.containsKey(META_DATA_KEY_ORDER) + return mMetaData != null + && mMetaData.containsKey(META_DATA_KEY_ORDER) && mMetaData.get(META_DATA_KEY_ORDER) instanceof Integer; } @@ -204,7 +205,7 @@ public abstract class Tile implements Parcelable { CharSequence title = null; ensureMetadataNotStale(context); final PackageManager packageManager = context.getPackageManager(); - if (mMetaData.containsKey(META_DATA_PREFERENCE_TITLE)) { + if (mMetaData != null && mMetaData.containsKey(META_DATA_PREFERENCE_TITLE)) { if (mMetaData.containsKey(META_DATA_PREFERENCE_TITLE_URI)) { // If has as uri to provide dynamic title, skip loading here. UI will later load // at tile binding time. @@ -284,10 +285,10 @@ public abstract class Tile implements Parcelable { * Optional key to use for this tile. */ public String getKey(Context context) { + ensureMetadataNotStale(context); if (!hasKey()) { return null; } - ensureMetadataNotStale(context); if (mMetaData.get(META_DATA_PREFERENCE_KEYHINT) instanceof Integer) { return context.getResources().getString(mMetaData.getInt(META_DATA_PREFERENCE_KEYHINT)); } else { diff --git a/packages/SettingsLib/res/drawable/ic_hotspot_auto.xml b/packages/SettingsLib/res/drawable/ic_hotspot_auto.xml new file mode 100644 index 000000000000..ddd526ada46d --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_hotspot_auto.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M240,760L240,800Q240,817 228.5,828.5Q217,840 200,840L160,840Q143,840 131.5,828.5Q120,817 120,800L120,480L204,240Q210,222 225.5,211Q241,200 260,200L700,200Q719,200 734.5,211Q750,222 756,240L840,480L840,800Q840,817 828.5,828.5Q817,840 800,840L760,840Q743,840 731.5,828.5Q720,817 720,800L720,760L240,760ZM232,400L728,400L686,280L274,280L232,400ZM200,480L200,480L200,680L200,680L200,480ZM300,640Q325,640 342.5,622.5Q360,605 360,580Q360,555 342.5,537.5Q325,520 300,520Q275,520 257.5,537.5Q240,555 240,580Q240,605 257.5,622.5Q275,640 300,640ZM660,640Q685,640 702.5,622.5Q720,605 720,580Q720,555 702.5,537.5Q685,520 660,520Q635,520 617.5,537.5Q600,555 600,580Q600,605 617.5,622.5Q635,640 660,640ZM200,680L760,680L760,480L200,480L200,680Z"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_hotspot_laptop.xml b/packages/SettingsLib/res/drawable/ic_hotspot_laptop.xml new file mode 100644 index 000000000000..5e1b184c2a5a --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_hotspot_laptop.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M0,800L0,720L80,720L80,120L880,120L880,720L960,720L960,800L0,800ZM400,720L560,720L560,680L400,680L400,720ZM160,600L800,600L800,200L160,200L160,600ZM160,600L160,200L160,200L160,600L160,600Z"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_hotspot_phone.xml b/packages/SettingsLib/res/drawable/ic_hotspot_phone.xml new file mode 100644 index 000000000000..baa793c0e9c1 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_hotspot_phone.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M280,920Q247,920 223.5,896.5Q200,873 200,840L200,120Q200,87 223.5,63.5Q247,40 280,40L680,40Q713,40 736.5,63.5Q760,87 760,120L760,840Q760,873 736.5,896.5Q713,920 680,920L280,920ZM280,800L280,840Q280,840 280,840Q280,840 280,840L680,840Q680,840 680,840Q680,840 680,840L680,800L280,800ZM280,720L680,720L680,240L280,240L280,720ZM280,160L680,160L680,120Q680,120 680,120Q680,120 680,120L280,120Q280,120 280,120Q280,120 280,120L280,160ZM280,160L280,120Q280,120 280,120Q280,120 280,120L280,120Q280,120 280,120Q280,120 280,120L280,160L280,160ZM280,800L280,800L280,840Q280,840 280,840Q280,840 280,840L280,840Q280,840 280,840Q280,840 280,840L280,800Z"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_hotspot_tablet.xml b/packages/SettingsLib/res/drawable/ic_hotspot_tablet.xml new file mode 100644 index 000000000000..cf67cd9e2b77 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_hotspot_tablet.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M120,800Q87,800 63.5,776.5Q40,753 40,720L40,240Q40,207 63.5,183.5Q87,160 120,160L840,160Q873,160 896.5,183.5Q920,207 920,240L920,720Q920,753 896.5,776.5Q873,800 840,800L120,800ZM160,240L120,240Q120,240 120,240Q120,240 120,240L120,720Q120,720 120,720Q120,720 120,720L160,720L160,240ZM240,720L720,720L720,240L240,240L240,720ZM800,240L800,720L840,720Q840,720 840,720Q840,720 840,720L840,240Q840,240 840,240Q840,240 840,240L800,240ZM800,240L840,240Q840,240 840,240Q840,240 840,240L840,240Q840,240 840,240Q840,240 840,240L800,240L800,240ZM160,240L160,240L120,240Q120,240 120,240Q120,240 120,240L120,240Q120,240 120,240Q120,240 120,240L160,240Z"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_hotspot_watch.xml b/packages/SettingsLib/res/drawable/ic_hotspot_watch.xml new file mode 100644 index 000000000000..252a0dbd62b2 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_hotspot_watch.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M360,880L306,698Q258,660 229,603Q200,546 200,480Q200,414 229,357Q258,300 306,262L360,80L600,80L654,262Q702,300 731,357Q760,414 760,480Q760,546 731,603Q702,660 654,698L600,880L360,880ZM480,680Q563,680 621.5,621.5Q680,563 680,480Q680,397 621.5,338.5Q563,280 480,280Q397,280 338.5,338.5Q280,397 280,480Q280,563 338.5,621.5Q397,680 480,680ZM404,210Q424,205 442.5,202Q461,199 480,199Q499,199 517.5,202Q536,205 556,210L540,160L420,160L404,210ZM420,800L540,800L556,750Q536,755 517.5,757.5Q499,760 480,760Q461,760 442.5,757.5Q424,755 404,750L420,800ZM404,160L420,160L540,160L556,160Q536,160 517.5,160Q499,160 480,160Q461,160 442.5,160Q424,160 404,160ZM420,800L404,800Q424,800 442.5,800Q461,800 480,800Q499,800 517.5,800Q536,800 556,800L540,800L420,800Z"/> +</vector> diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml index 3b980c5a5770..17d5e1d7fb34 100644 --- a/packages/SettingsLib/res/values-eu/arrays.xml +++ b/packages/SettingsLib/res/values-eu/arrays.xml @@ -208,7 +208,7 @@ <item msgid="2675263395797191850">"Animazioa desaktibatuta"</item> <item msgid="5790132543372767872">"Animazio-eskala: 0,5x"</item> <item msgid="2529692189302148746">"Animazio-eskala: 1×"</item> - <item msgid="8072785072237082286">"Animazio-eskala: 1,5x"</item> + <item msgid="8072785072237082286">"Animazio-eskala: 1,5×"</item> <item msgid="3531560925718232560">"Animazio-eskala 2x"</item> <item msgid="4542853094898215187">"Animazio-eskala: 5x"</item> <item msgid="5643881346223901195">"Animazio-eskala: 10x"</item> @@ -217,7 +217,7 @@ <item msgid="3376676813923486384">"Animazioa desaktibatuta"</item> <item msgid="753422683600269114">"Animazio-eskala: 0,5x"</item> <item msgid="3695427132155563489">"Animazio-eskala: 1×"</item> - <item msgid="9032615844198098981">"Animazio-eskala: 1,5x"</item> + <item msgid="9032615844198098981">"Animazio-eskala: 1,5×"</item> <item msgid="8473868962499332073">"Animazio-eskala: 2x"</item> <item msgid="4403482320438668316">"Animazio-eskala: 5x"</item> <item msgid="169579387974966641">"Animazio-eskala: 10x"</item> @@ -226,7 +226,7 @@ <item msgid="6416998593844817378">"Animazioa desaktibatuta"</item> <item msgid="875345630014338616">"Animazio-eskala: 0,5x"</item> <item msgid="2753729231187104962">"Animazio-eskala: 1×"</item> - <item msgid="1368370459723665338">"Animazio-eskala: 1,5x"</item> + <item msgid="1368370459723665338">"Animazio-eskala: 1,5×"</item> <item msgid="5768005350534383389">"Animazio-eskala: 2x"</item> <item msgid="3728265127284005444">"Animazio-eskala: 5x"</item> <item msgid="2464080977843960236">"Animazio-eskala: 10x"</item> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index afab0469d114..b9a464752824 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -27,6 +27,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiInfo; +import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; @@ -331,6 +332,22 @@ public class WifiUtils { } /** + * Returns the Hotspot network icon resource. + * + * @param deviceType The device type of Hotspot network + */ + public static int getHotspotIconResource(int deviceType) { + return switch (deviceType) { + case NetworkProviderInfo.DEVICE_TYPE_PHONE -> R.drawable.ic_hotspot_phone; + case NetworkProviderInfo.DEVICE_TYPE_TABLET -> R.drawable.ic_hotspot_tablet; + case NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> R.drawable.ic_hotspot_laptop; + case NetworkProviderInfo.DEVICE_TYPE_WATCH -> R.drawable.ic_hotspot_watch; + case NetworkProviderInfo.DEVICE_TYPE_AUTO -> R.drawable.ic_hotspot_auto; + default -> R.drawable.ic_hotspot_phone; // Return phone icon as default. + }; + } + + /** * Wrapper the {@link #getInternetIconResource} for testing compatibility. */ public static class InternetIconInjector { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java index b60dc6ae8de1..529301138da3 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java @@ -35,6 +35,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.net.wifi.WifiNetworkScoreCache; +import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; @@ -201,6 +202,25 @@ public class WifiUtilsTest { } @Test + public void getHotspotIconResource_deviceTypeUnknown_shouldNotCrash() { + WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_UNKNOWN); + } + + @Test + public void getHotspotIconResource_deviceTypeExists_shouldNotNull() { + assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_PHONE)) + .isNotNull(); + assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_TABLET)) + .isNotNull(); + assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_LAPTOP)) + .isNotNull(); + assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_WATCH)) + .isNotNull(); + assertThat(WifiUtils.getHotspotIconResource(NetworkProviderInfo.DEVICE_TYPE_AUTO)) + .isNotNull(); + } + + @Test public void testInternetIconInjector_getIcon_returnsCorrectValues() { WifiUtils.InternetIconInjector iconInjector = new WifiUtils.InternetIconInjector(mContext); diff --git a/packages/Shell/res/values-gl/strings.xml b/packages/Shell/res/values-gl/strings.xml index 912dc85e15e4..9d4f7de68793 100644 --- a/packages/Shell/res/values-gl/strings.xml +++ b/packages/Shell/res/values-gl/strings.xml @@ -20,7 +20,7 @@ <string name="bugreport_notification_channel" msgid="2574150205913861141">"Informes de erros"</string> <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Estase xerando o informe de erros <xliff:g id="ID">#%d</xliff:g>"</string> <string name="bugreport_finished_title" msgid="4429132808670114081">"Rexistrouse o informe de erros <xliff:g id="ID">#%d</xliff:g>"</string> - <string name="bugreport_updating_title" msgid="4423539949559634214">"Engadindo detalles ao informe de erro"</string> + <string name="bugreport_updating_title" msgid="4423539949559634214">"Engadindo detalles ao informe de erros"</string> <string name="bugreport_updating_wait" msgid="3322151947853929470">"Agarda..."</string> <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"O informe de erros aparecerá no teléfono en breve"</string> <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Selecciona para compartir o teu informe de erros"</string> @@ -32,7 +32,7 @@ <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Non mostrar outra vez"</string> <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de erros"</string> <string name="bugreport_unreadable_text" msgid="586517851044535486">"Non se puido ler o ficheiro de informe de erros"</string> - <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Non se puideron engadir os detalles do informe de erro ao ficheiro zip"</string> + <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Non se puideron engadir os detalles do informe de erros ao ficheiro zip"</string> <string name="bugreport_unnamed" msgid="2800582406842092709">"sen nome"</string> <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string> <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string> diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt index 8e79e3ce1742..38b99cc5f5ee 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt @@ -70,6 +70,9 @@ class ViewHierarchyAnimator { * If a new layout change happens while an animation is already in progress, the animation * is updated to continue from the current values to the new end state. * + * A set of [excludedViews] can be passed. If any dependent view from [rootView] matches an + * entry in this set, changes to that view will not be animated. + * * The animator continues to respond to layout changes until [stopAnimating] is called. * * Successive calls to this method override the previous settings ([interpolator] and @@ -82,9 +85,16 @@ class ViewHierarchyAnimator { fun animate( rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, - duration: Long = DEFAULT_DURATION + duration: Long = DEFAULT_DURATION, + excludedViews: Set<View> = emptySet() ): Boolean { - return animate(rootView, interpolator, duration, ephemeral = false) + return animate( + rootView, + interpolator, + duration, + ephemeral = false, + excludedViews = excludedViews + ) } /** @@ -95,16 +105,24 @@ class ViewHierarchyAnimator { fun animateNextUpdate( rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, - duration: Long = DEFAULT_DURATION + duration: Long = DEFAULT_DURATION, + excludedViews: Set<View> = emptySet() ): Boolean { - return animate(rootView, interpolator, duration, ephemeral = true) + return animate( + rootView, + interpolator, + duration, + ephemeral = true, + excludedViews = excludedViews + ) } private fun animate( rootView: View, interpolator: Interpolator, duration: Long, - ephemeral: Boolean + ephemeral: Boolean, + excludedViews: Set<View> = emptySet() ): Boolean { if ( !occupiesSpace( @@ -119,7 +137,7 @@ class ViewHierarchyAnimator { } val listener = createUpdateListener(interpolator, duration, ephemeral) - addListener(rootView, listener, recursive = true) + addListener(rootView, listener, recursive = true, excludedViews = excludedViews) return true } @@ -921,8 +939,11 @@ class ViewHierarchyAnimator { private fun addListener( view: View, listener: View.OnLayoutChangeListener, - recursive: Boolean = false + recursive: Boolean = false, + excludedViews: Set<View> = emptySet() ) { + if (excludedViews.contains(view)) return + // Make sure that only one listener is active at a time. val previousListener = view.getTag(R.id.tag_layout_listener) if (previousListener != null && previousListener is View.OnLayoutChangeListener) { @@ -933,7 +954,12 @@ class ViewHierarchyAnimator { view.setTag(R.id.tag_layout_listener, listener) if (view is ViewGroup && recursive) { for (i in 0 until view.childCount) { - addListener(view.getChildAt(i), listener, recursive = true) + addListener( + view.getChildAt(i), + listener, + recursive = true, + excludedViews = excludedViews + ) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index ca91b8a21a81..38b751c9445d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -17,15 +17,19 @@ package com.android.systemui.notifications.ui.composable +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp @Composable @@ -34,10 +38,26 @@ fun Notifications( ) { // TODO(b/272779828): implement. Column( - modifier = modifier.fillMaxWidth().defaultMinSize(minHeight = 300.dp).padding(4.dp), + modifier = + modifier + .fillMaxWidth() + .defaultMinSize(minHeight = 300.dp) + .clip(RoundedCornerShape(32.dp)) + .background(MaterialTheme.colorScheme.surface) + .padding(16.dp), ) { - Text("Notifications", modifier = Modifier.align(Alignment.CenterHorizontally)) + Text( + text = "Notifications", + modifier = Modifier.align(Alignment.CenterHorizontally), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + ) Spacer(modifier = Modifier.weight(1f)) - Text("Shelf", modifier = Modifier.align(Alignment.CenterHorizontally)) + Text( + text = "Shelf", + modifier = Modifier.align(Alignment.CenterHorizontally), + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.onSurface, + ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt index 665d6dd0cfa2..1bb341c76e69 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt @@ -17,15 +17,19 @@ package com.android.systemui.qs.footer.ui.compose +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp @Composable @@ -34,10 +38,26 @@ fun QuickSettings( ) { // TODO(b/272780058): implement. Column( - modifier = modifier.fillMaxWidth().defaultMinSize(minHeight = 300.dp).padding(4.dp), + modifier = + modifier + .fillMaxWidth() + .defaultMinSize(minHeight = 300.dp) + .clip(RoundedCornerShape(32.dp)) + .background(MaterialTheme.colorScheme.primary) + .padding(16.dp), ) { - Text("Quick settings", modifier = Modifier.align(Alignment.CenterHorizontally)) + Text( + text = "Quick settings", + modifier = Modifier.align(Alignment.CenterHorizontally), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onPrimary, + ) Spacer(modifier = Modifier.weight(1f)) - Text("QS footer actions", modifier = Modifier.align(Alignment.CenterHorizontally)) + Text( + text = "QS footer actions", + modifier = Modifier.align(Alignment.CenterHorizontally), + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.onPrimary, + ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 20e175160aa6..27358f53aaf2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -16,18 +16,19 @@ package com.android.systemui.shade.ui.composable +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.material3.Button -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding 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.dagger.qualifiers.Application +import com.android.systemui.notifications.ui.composable.Notifications +import com.android.systemui.qs.footer.ui.compose.QuickSettings import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel @@ -62,12 +63,7 @@ class ShadeScene( override fun Content( containerName: String, modifier: Modifier, - ) { - ShadeScene( - viewModel = viewModel, - modifier = modifier, - ) - } + ) = ShadeScene(viewModel, modifier) private fun destinationScenes( up: SceneKey, @@ -84,23 +80,15 @@ private fun ShadeScene( viewModel: ShadeSceneViewModel, modifier: Modifier = Modifier, ) { - // TODO(b/280887022): implement the real UI. - - Box(modifier = modifier) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.align(Alignment.Center) - ) { - Text("Shade", style = MaterialTheme.typography.headlineMedium) - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - Button( - onClick = { viewModel.onContentClicked() }, - ) { - Text("Open some content") - } - } - } + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = + Modifier.fillMaxSize() + .clickable(onClick = { viewModel.onContentClicked() }) + .padding(horizontal = 16.dp, vertical = 48.dp) + ) { + QuickSettings(modifier = modifier.height(160.dp)) + Notifications(modifier = modifier.weight(1f)) } } diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt index 18753fd9c0c7..006fc09fb400 100644 --- a/packages/SystemUI/ktfmt_includes.txt +++ b/packages/SystemUI/ktfmt_includes.txt @@ -422,9 +422,6 @@ -packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt -packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLogger.kt -packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt @@ -696,7 +693,6 @@ -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml index 57b3acd6557a..66c54f2a668e 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml @@ -21,6 +21,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/keyguard_lock_padding" + android:importantForAccessibility="no" android:ellipsize="marquee" android:focusable="true" android:gravity="center" diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml deleted file mode 100644 index 9304ff72f054..000000000000 --- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml +++ /dev/null @@ -1,136 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 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 - --> - -<!-- Layout for media recommendations inside QSPanel carousel --> -<!-- See media_recommendation_expanded.xml and media_recommendation_collapsed.xml for the - constraints. --> -<com.android.systemui.util.animation.TransitionLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/media_recommendations" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clipChildren="false" - android:clipToPadding="false" - android:forceHasOverlappingRendering="false" - android:background="@drawable/qs_media_background" - android:theme="@style/MediaPlayer"> - - <!-- This view just ensures the full media player is a certain height. --> - <View - android:id="@+id/sizing_view" - android:layout_width="match_parent" - android:layout_height="@dimen/qs_media_session_height_expanded" /> - - <com.android.internal.widget.CachingIconView - android:id="@+id/recommendation_card_icon" - android:layout_width="@dimen/qs_media_app_icon_size" - android:layout_height="@dimen/qs_media_app_icon_size" - android:minWidth="@dimen/qs_media_app_icon_size" - android:minHeight="@dimen/qs_media_app_icon_size" - android:layout_marginStart="@dimen/qs_media_padding" - android:layout_marginTop="@dimen/qs_media_rec_icon_top_margin" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - <FrameLayout - android:id="@+id/media_cover1_container" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - > - <ImageView - android:id="@+id/media_cover1" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:minWidth="@dimen/qs_media_rec_album_size" - android:minHeight="@dimen/qs_media_rec_album_size" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - android:adjustViewBounds="true" - android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Recommendation.Album" - android:clipToOutline="true" - android:scaleType="centerCrop"/> - </FrameLayout> - - <TextView - android:id="@+id/media_title1" - style="@style/MediaPlayer.Recommendation.Text.Title" - /> - - <TextView - android:id="@+id/media_subtitle1" - style="@style/MediaPlayer.Recommendation.Text.Subtitle" - /> - - <FrameLayout - android:id="@+id/media_cover2_container" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - > - <ImageView - android:id="@+id/media_cover2" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:minWidth="@dimen/qs_media_rec_album_size" - android:minHeight="@dimen/qs_media_rec_album_size" - android:adjustViewBounds="true" - android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Recommendation.Album" - android:clipToOutline="true" - android:scaleType="centerCrop"/> - </FrameLayout> - - <TextView - android:id="@+id/media_title2" - style="@style/MediaPlayer.Recommendation.Text.Title" - /> - - <TextView - android:id="@+id/media_subtitle2" - style="@style/MediaPlayer.Recommendation.Text.Subtitle" - /> - - <FrameLayout - android:id="@+id/media_cover3_container" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - > - <ImageView - android:id="@+id/media_cover3" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:minWidth="@dimen/qs_media_rec_album_size" - android:minHeight="@dimen/qs_media_rec_album_size" - android:adjustViewBounds="true" - android:background="@drawable/bg_smartspace_media_item" - style="@style/MediaPlayer.Recommendation.Album" - android:clipToOutline="true" - android:scaleType="centerCrop"/> - </FrameLayout> - - <TextView - android:id="@+id/media_title3" - style="@style/MediaPlayer.Recommendation.Text.Title" - /> - - <TextView - android:id="@+id/media_subtitle3" - style="@style/MediaPlayer.Recommendation.Text.Subtitle" - /> - - <include - layout="@layout/media_long_press_menu" /> - -</com.android.systemui.util.animation.TransitionLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 5bd2184a2608..e0c25e3ca3fb 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tik om te bekyk"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Kon nie skermopname stoor nie"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Kon nie skermopname begin nie"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Bekyk tans volskerm"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Swiep van bo af as jy wil uitgaan."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Het dit"</string> <string name="accessibility_back" msgid="6530104400086152611">"Terug"</string> <string name="accessibility_home" msgid="5430449841237966217">"Tuis"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Kieslys"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Wanneer jy deel, opneem of uitsaai, het Android toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Wanneer jy ’n app deel, opneem of uitsaai, het Android toegang tot enigiets wat in daardie app gewys of gespeel word. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Begin"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Deur jou IT-admin geblokkeer"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Skermskote is deur toestelbeleid gedeaktiveer"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Vee alles uit"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index f2eb7669c4a7..b8ac5fc74ca6 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ለመመልከት መታ ያድርጉ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"የማያ ገጽ ቀረጻን ማስቀመጥ ላይ ስህተት"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"የማያ ገፅ ቀረጻን መጀመር ላይ ስህተት"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ሙሉ ገፅ በማሳየት ላይ"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ለመውጣት፣ ከላይ ወደታች ጠረግ ያድርጉ።"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ገባኝ"</string> <string name="accessibility_back" msgid="6530104400086152611">"ተመለስ"</string> <string name="accessibility_home" msgid="5430449841237966217">"መነሻ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"ምናሌ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"እርስዎ ሲያጋሩ፣ ሲቀርጹ ወይም cast ሲያደርጉ Android በማያ ገጽዎ ላይ ለሚታይ ወይም በመሣሪያዎ ላይ ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"እርስዎ ሲያጋሩ፣ ሲቀርጹ ወይም cast ሲያደርጉ Android በማያ ገጽዎ ላይ ለሚታይ ወይም በመሣሪያዎ ላይ ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ጀምር"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"በእርስዎ የአይቲ አስተዳዳሪ ታግዷል"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"የማያ ገፅ ቀረጻ በመሣሪያ መመሪያ ተሰናክሏል"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ሁሉንም አጽዳ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 9a74144ce79e..e4657735ae85 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"انقر لعرض التسجيل."</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"حدث خطأ أثناء حفظ تسجيل محتوى الشاشة."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"جارٍ العرض بملء الشاشة"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"للخروج، مرر بسرعة من أعلى إلى أسفل."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"حسنًا"</string> <string name="accessibility_back" msgid="6530104400086152611">"رجوع"</string> <string name="accessibility_home" msgid="5430449841237966217">"الرئيسية"</string> <string name="accessibility_menu" msgid="2701163794470513040">"القائمة"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"أثناء المشاركة أو التسجيل أو البثّ، يمكن لنظام Android الوصول إلى كل المحتوى المعروض على شاشتك أو الذي يتم تشغيله على جهازك، لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"أثناء مشاركة محتوى تطبيق أو تسجيله أو بثّه، يمكن لنظام Android الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله في ذلك التطبيق، لذا يُرجى توخي الحذر بشأن المعلومات مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"بدء"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"حظر مشرف تكنولوجيا المعلومات هذه الميزة"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ميزة \"تصوير الشاشة\" غير مفعَّلة بسبب سياسة الجهاز."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"محو الكل"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 856989cd400b..372cab8e9816 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"চাবলৈ টিপক"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ৰেকৰ্ড কৰা স্ক্ৰীন ছেভ কৰোঁতে আসোঁৱাহ হৈছে"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রীন ৰেকৰ্ড কৰা আৰম্ভ কৰোঁতে আসোঁৱাহ হৈছে"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"পূৰ্ণ স্ক্ৰীনত চাই আছে"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"বাহিৰ হ’বলৈ ওপৰৰ পৰা তললৈ ছোৱাইপ কৰক।"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"বুজি পালোঁ"</string> <string name="accessibility_back" msgid="6530104400086152611">"উভতি যাওক"</string> <string name="accessibility_home" msgid="5430449841237966217">"গৃহ পৃষ্ঠাৰ বুটাম"</string> <string name="accessibility_menu" msgid="2701163794470513040">"মেনু"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"আপুনি শ্বেয়াৰ কৰা, ৰেকৰ্ড কৰা অথবা কাষ্ট কৰাৰ সময়ত, আপোনাৰ স্ক্ৰীনখনত দৃশ্যমান হোৱা যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ Androidৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"আপুনি শ্বেয়াৰ কৰা, ৰেকৰ্ড কৰা অথবা কাষ্ট কৰাৰ সময়ত, সেইটো এপত দৃশ্যমান যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ Androidৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"আৰম্ভ কৰক"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"আপোনাৰ আইটি প্ৰশাসকে অৱৰোধ কৰিছে"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ডিভাইচ সম্পৰ্কীয় নীতিয়ে স্ক্ৰীন কেপশ্বাৰ কৰাটো অক্ষম কৰিছে"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"আটাইবোৰ মচক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 1c14b04ebf05..ba87178ad5f4 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Baxmaq üçün toxunun"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Ekran çəkimini yadda saxlayarkən xəta oldu"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranın yazılması ilə bağlı xəta"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Tam ekrana baxış"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Çıxmaq üçün yuxarıdan aşağı sürüşdürün."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Anladım"</string> <string name="accessibility_back" msgid="6530104400086152611">"Geri"</string> <string name="accessibility_home" msgid="5430449841237966217">"Ana səhifə"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menyu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Paylaşım, qeydəalma və ya yayım zamanı Android-in ekranda görünən, yaxud cihazda oxudulan məlumatlara girişi olur. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Tətbiq paylaşdıqda, qeydə aldıqda və ya yayımladıqda Android-in həmin tətbiqdə göstərilən, yaxud oxudulan məlumatlara girişi olur. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Başlayın"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"İT admininiz tərəfindən bloklanıb"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ekran çəkimi cihaz siyasəti ilə deaktiv edilib"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hamısını silin"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index c00cd6a6dd33..258ae1d2d215 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Dodirnite da biste pregledali"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Greška pri čuvanju snimka ekrana"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Prikazuje se ceo ekran"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Da biste izašli, prevucite nadole odozgo."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Važi"</string> <string name="accessibility_back" msgid="6530104400086152611">"Nazad"</string> <string name="accessibility_home" msgid="5430449841237966217">"Početna"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Meni"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kada delite, snimate ili prebacujete, Android ima pristup kompletnom sadržaju koji je vidljiv na ekranu ili se pušta na uređaju. Zato budite pažljivi sa lozinkama, informacijama o plaćanju, porukama, slikama i audio i video snimcima."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kada delite, snimate ili prebacujete aplikaciju, Android ima pristup kompletnom sadržaju koji je vidljiv ili se pušta u toj aplikaciji. Zato budite pažljivi sa lozinkama, informacijama o plaćanju, porukama, slikama i audio i video snimcima."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Pokreni"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokira IT administrator"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Snimanje ekrana je onemogućeno smernicama za uređaj"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 95eebada5318..5f9d63ccfb4a 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Націсніце для прагляду"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Памылка захавання запісу экрана"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Памылка пачатку запісу экрана"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Прагляд у поўнаэкранным рэжыме"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Для выхаду правядзіце зверху ўніз."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Зразумела"</string> <string name="accessibility_back" msgid="6530104400086152611">"Назад"</string> <string name="accessibility_home" msgid="5430449841237966217">"На Галоўную старонку"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Меню"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Калі адбываецца абагульванне, запіс ці трансляцыя, Android мае доступ да ўсяго змесціва, якое паказваецца на экране ці прайграецца на прыладзе. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Калі адбываецца абагульванне, запіс ці трансляцыя змесціва праграмы, Android мае доступ да ўсяго змесціва, якое паказваецца ці прайграецца ў праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Пачаць"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Заблакіравана вашым ІТ-адміністратарам"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Здыманне экрана адключана згодна з палітыкай прылады"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Ачысціць усё"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 567a22b606b5..f2a8dbf1bc9d 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Докоснете за преглед"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Грешка при запазването на записа на екрана"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"При стартирането на записа на екрана възникна грешка"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Изглед на цял екран"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"За изход плъзнете пръст надолу от горната част."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Разбрах"</string> <string name="accessibility_back" msgid="6530104400086152611">"Назад"</string> <string name="accessibility_home" msgid="5430449841237966217">"Начало"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Меню"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Когато споделяте, записвате или предавате, Android има достъп до всичко, което се вижда на екрана ви или се възпроизвежда на устройството ви. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Когато споделяте, записвате или предавате дадено приложение, Android има достъп до всичко, което се показва или възпроизвежда в него. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Стартиране"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Блокирано от системния ви администратор"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Заснемането на екрана е деактивирано от правило за устройството"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 38308e274a41..836b0edfe736 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"দেখতে ট্যাপ করুন"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"স্ক্রিন রেকর্ডিং সেভ করার সময় কোনও সমস্যা হয়েছে"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রিন রেকর্ডিং শুরু করার সময় সমস্যা হয়েছে"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ফুল-স্ক্রিনে দেখা হচ্ছে"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"বেরিয়ে যেতে উপর থেকে নিচের দিকে সোয়াইপ করুন।"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"বুঝেছি"</string> <string name="accessibility_back" msgid="6530104400086152611">"ফিরুন"</string> <string name="accessibility_home" msgid="5430449841237966217">"হোম"</string> <string name="accessibility_menu" msgid="2701163794470513040">"মেনু"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"আপনি শেয়ার, রেকর্ড বা কাস্ট করার সময়, স্ক্রিনে দৃশ্যমান বা ডিভাইসে চালানো সব কিছুই Android অ্যাক্সেস করতে পারবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"আপনি কোনও অ্যাপ শেয়ার, রেকর্ড বা কাস্ট করার সময়, সেই অ্যাপে দেখা যায় বা চালানো হয় এমন সব কিছু Android অ্যাক্সেস করতে পারবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"শুরু করুন"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"আপনার আইটি অ্যাডমিন ব্লক করেছেন"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ডিভাইস নীতির কারণে স্ক্রিন ক্যাপচার করার প্রসেস বন্ধ করা আছে"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"সব মুছে দিন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index eaa0d9d1dec2..db902ef0b2b2 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Dodirnite da vidite"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Greška prilikom pohranjivanja snimka ekrana"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Prikazuje se cijeli ekran"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Da izađete, prevucite odozgo nadolje."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Razumijem"</string> <string name="accessibility_back" msgid="6530104400086152611">"Nazad"</string> <string name="accessibility_home" msgid="5430449841237966217">"Dugme za početnu stranicu"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Dugme Meni"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kada dijelite, snimate ili emitirate, Android ima pristup svemu što je vidljivo na ekranu ili što se reproducira na uređaju. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kada dijelite, snimate ili emitirate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Pokreni"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokirao je vaš IT administrator"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Snimanje ekrana je onemogućeno pravilima uređaja"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Očisti sve"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 6416543d3f1b..7eefa4fbee87 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Toca per veure-la"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"S\'ha produït un error en desar la gravació de la pantalla"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"S\'ha produït un error en iniciar la gravació de pantalla"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Mode de pantalla completa"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Per sortir, llisca cap avall des de la part superior."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Entesos"</string> <string name="accessibility_back" msgid="6530104400086152611">"Enrere"</string> <string name="accessibility_home" msgid="5430449841237966217">"Inici"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menú"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Quan comparteixes, graves o emets contingut, Android té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi al dispositiu. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Quan comparteixes, graves o emets contingut, Android té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi a l\'aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Inicia"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloquejat per l\'administrador de TI"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Les captures de pantalla estan desactivades per la política de dispositius"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Esborra-ho tot"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 56ae4b8ca0a3..4a070fbafe84 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Klepnutím nahrávku zobrazíte"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Při ukládání záznamu obrazovky došlo k chybě"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Při spouštění nahrávání obrazovky došlo k chybě"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Zobrazení celé obrazovky"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Režim ukončíte přejetím prstem shora dolů."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Rozumím"</string> <string name="accessibility_back" msgid="6530104400086152611">"Zpět"</string> <string name="accessibility_home" msgid="5430449841237966217">"Domů"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Během sdílení, nahrávání nebo odesílání má Android přístup k veškerému obsahu, který je viditelný na obrazovce nebo se přehrává v zařízení. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Během sdílení, nahrávání nebo odesílání aplikace má Android přístup k veškerému obsahu, který je v dané aplikaci zobrazen nebo přehráván. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Začít"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokováno administrátorem IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Záznam obrazovky je zakázán zásadami zařízení"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Smazat vše"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 0ce993226988..2893b1e94a0e 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tryk for at se"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Skærmoptagelsen kunne ikke gemmes"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Skærmoptagelsen kunne ikke startes"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visning i fuld skærm"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Stryg ned fra toppen for at afslutte."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK, det er forstået"</string> <string name="accessibility_back" msgid="6530104400086152611">"Tilbage"</string> <string name="accessibility_home" msgid="5430449841237966217">"Hjem"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Når du deler, optager eller caster, har Android adgang til alt, der er synligt på din skærm eller afspilles på din enhed. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Når du deler, optager eller caster en app, har Android adgang til alt, der vises eller afspilles i den pågældende app. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Start"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokeret af din it-administrator"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screenshots er deaktiveret af enhedspolitikken"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index ef76528af1a7..b52754117dcf 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Zum Ansehen tippen"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Fehler beim Speichern der Bildschirmaufzeichnung"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Fehler beim Start der Bildschirmaufzeichnung"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Vollbildmodus wird aktiviert"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Zum Beenden von oben nach unten wischen"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Ok"</string> <string name="accessibility_back" msgid="6530104400086152611">"Zurück"</string> <string name="accessibility_home" msgid="5430449841237966217">"Startbildschirm"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menü"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Beim Teilen, Aufnehmen oder Streamen hat Android Zugriff auf alle Inhalte, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Beim Teilen, Aufnehmen oder Streamen einer App hat Android Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder von ihr wiedergegeben werden. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Starten"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Vom IT-Administrator blockiert"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Bildschirmaufnahme ist durch die Geräterichtlinien deaktiviert"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Alle löschen"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 2c4b33221d44..e23cbb8b5a34 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Πατήστε για προβολή"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Σφάλμα κατά την αποθήκευση της εγγραφής οθόνης"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Σφάλμα κατά την έναρξη της εγγραφής οθόνης"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Προβολή σε πλήρη οθόνη"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Για έξοδο, σύρετε προς τα κάτω από το επάνω μέρος."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Το κατάλαβα"</string> <string name="accessibility_back" msgid="6530104400086152611">"Πίσω"</string> <string name="accessibility_home" msgid="5430449841237966217">"Αρχική οθόνη"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Μενού"</string> @@ -412,6 +415,10 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Όταν κάνετε κοινή χρήση, εγγραφή ή μετάδοση, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη σας ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Όταν κάνετε κοινή χρήση, εγγραφή ή μετάδοση μιας εφαρμογής, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Έναρξη"</string> + <string name="media_projection_task_switcher_text" msgid="590885489897412359">"Η κοινοποίηση τίθεται σε παύση κατά την εναλλαγή μεταξύ εφαρμογών"</string> + <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Εναλλακτικά, κοινοποιήστε την εφαρμογή"</string> + <string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Επιστροφή"</string> + <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Εναλλαγή μεταξύ εφαρμογών"</string> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Αποκλείστηκε από τον διαχειριστή IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Η καταγραφή οθόνης έχει απενεργοποιηθεί από την πολιτική χρήσης συσκευής."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Διαγραφή όλων"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 03d2a510ed68..809873974955 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string> <string name="accessibility_back" msgid="6530104400086152611">"Back"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"When you’re sharing, recording or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"When you’re sharing, recording or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Start"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index f328508efc74..d20838262722 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string> <string name="accessibility_back" msgid="6530104400086152611">"Back"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,10 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"When you’re sharing, recording, or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"When you’re sharing, recording, or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Start"</string> + <string name="media_projection_task_switcher_text" msgid="590885489897412359">"Sharing pauses when you switch apps"</string> + <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Share this app instead"</string> + <string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Switch back"</string> + <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"App switch"</string> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 03d2a510ed68..809873974955 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string> <string name="accessibility_back" msgid="6530104400086152611">"Back"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"When you’re sharing, recording or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"When you’re sharing, recording or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Start"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 03d2a510ed68..809873974955 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string> <string name="accessibility_back" msgid="6530104400086152611">"Back"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"When you’re sharing, recording or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"When you’re sharing, recording or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Start"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index ed958d839e7a..8a321e2434d8 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tap to view"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Error saving screen recording"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Got it"</string> <string name="accessibility_back" msgid="6530104400086152611">"Back"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,10 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"When you’re sharing, recording, or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"When you’re sharing, recording, or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Start"</string> + <string name="media_projection_task_switcher_text" msgid="590885489897412359">"Sharing pauses when you switch apps"</string> + <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Share this app instead"</string> + <string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Switch back"</string> + <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"App switch"</string> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 91b6be6c1529..a6edfd56711b 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Presiona para ver"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Se produjo un error al guardar la grabación de pantalla"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error al iniciar la grabación de pantalla"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visualización en pantalla completa"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Para salir, desliza el dedo hacia abajo desde la parte superior."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Entendido"</string> <string name="accessibility_back" msgid="6530104400086152611">"Atrás"</string> <string name="accessibility_home" msgid="5430449841237966217">"Página principal"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menú"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Cuando compartas, grabes o transmitas contenido, Android podrá acceder a todo lo que sea visible en la pantalla o que reproduzcas en el dispositivo. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Cuando compartas, grabes o transmitas una app, Android podrá acceder a todo el contenido que se muestre o que reproduzcas en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Iniciar"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloqueada por tu administrador de TI"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"La captura de pantalla está inhabilitada debido a la política del dispositivo"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Cerrar todo"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 178c8b15cc7a..2fb76cda3a6f 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Toca para verla"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"No se ha podido guardar la grabación de pantalla"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"No se ha podido empezar a grabar la pantalla"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Modo de pantalla completa"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Para salir, desliza el dedo de arriba abajo."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Entendido"</string> <string name="accessibility_back" msgid="6530104400086152611">"Atrás"</string> <string name="accessibility_home" msgid="5430449841237966217">"Inicio"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menú"</string> @@ -412,6 +415,10 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Cuando compartes, grabas o envías contenido, Android puede acceder a todo lo que se muestre en la pantalla o se reproduzca en tu dispositivo. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Cuando compartes, grabas o envías una aplicación, Android puede acceder a todo lo que se muestre o se reproduzca en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Empezar"</string> + <string name="media_projection_task_switcher_text" msgid="590885489897412359">"El uso compartido se detiene al cambiar de aplicación"</string> + <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Compartir esta aplicación"</string> + <string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Volver"</string> + <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Cambio de aplicación"</string> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloqueado por tu administrador de TI"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Las capturas de pantalla están inhabilitadas debido a la política de dispositivos"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string> @@ -1030,7 +1037,7 @@ <string name="status_before_loading" msgid="1500477307859631381">"El contenido se mostrará en breve"</string> <string name="missed_call" msgid="4228016077700161689">"Llamada perdida"</string> <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string> - <string name="people_tile_description" msgid="8154966188085545556">"Consulta los mensajes recientes, las llamadas perdidas y los cambios de estado"</string> + <string name="people_tile_description" msgid="8154966188085545556">"Consulta mensajes recientes, llamadas perdidas y cambios de estado"</string> <string name="people_tile_title" msgid="6589377493334871272">"Conversación"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Pausado por No molestar"</string> <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index b2470f7be334..b300e78505da 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Puudutage kuvamiseks"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Viga ekraanisalvestise salvestamisel"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Kuvamine täisekraanil"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Väljumiseks pühkige ülevalt alla."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Selge"</string> <string name="accessibility_back" msgid="6530104400086152611">"Tagasi"</string> <string name="accessibility_home" msgid="5430449841237966217">"Kodu"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menüü"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kui jagate, salvestate või kannate üle, on Androidil juurdepääs kõigele, mis on teie ekraanikuval nähtaval või mida teie seadmes esitatakse. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kui jagate, salvestate või kannate rakendust üle, on Androidil juurdepääs kõigele, mida selles rakenduses kuvatakse või esitatakse. Seega olge paroolide, makseteabe, sõnumite, fotode, heli ja videoga ettevaatlik."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Alusta"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokeeris teie IT-administraator"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ekraanikuva jäädvustamine on seadmereeglitega keelatud"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tühjenda kõik"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 33fee8d24398..8fd391c3ca20 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Sakatu ikusteko"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Errore bat gertatu da pantaila-grabaketa gordetzean"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Errore bat gertatu da pantaila grabatzen hastean"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Pantaila osoko ikuspegia"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Irteteko, pasatu hatza goitik behera."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Ados"</string> <string name="accessibility_back" msgid="6530104400086152611">"Atzera"</string> <string name="accessibility_home" msgid="5430449841237966217">"Hasiera"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menua"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Edukia partekatzen, grabatzen edo igortzen ari zarenean, pantailan ikusgai dagoen edo gailuan erreproduzitzen ari den guztia atzi dezake Android-ek. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Aplikazio bat partekatzen, grabatzen edo igortzen ari zarenean, aplikazio horretan ikusgai dagoen edo bertan erreproduzitzen ari den guztia atzi dezake Android-ek. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Hasi"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IKT saileko administratzaileak blokeatu du"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Pantaila-kapturak egiteko aukera desgaituta dago, gailu-gidalerroei jarraikiz"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Garbitu guztiak"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 97f6930afcac..4d3b3f00a2ea 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"برای مشاهده ضربه بزنید"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"خطا در ذخیرهسازی ضبط صفحهنمایش"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحهنمایش"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"درحال مشاهده در حالت تمامصفحه"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"برای خروج، از بالای صفحه تند بهپایین بکشید."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"متوجهام"</string> <string name="accessibility_back" msgid="6530104400086152611">"برگشت"</string> <string name="accessibility_home" msgid="5430449841237966217">"صفحهٔ اصلی"</string> <string name="accessibility_menu" msgid="2701163794470513040">"منو"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"وقتی درحال همرسانی، ضبط، یا پخش محتوا هستید، Android به همه محتوایی که در صفحهتان نمایان است یا در دستگاهتان پخش میشود دسترسی دارد. درنتیجه مراقب چیزهایی مثل گذرواژهها، جزئیات پرداخت، پیامها، عکسها، و صدا و تصویر باشید."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"وقتی درحال همرسانی، ضبط، یا پخش محتوای برنامهای هستید، Android به همه محتوایی که در آن برنامه نمایان است یا پخش میشود دسترسی دارد. درنتیجه مراقب چیزهایی مثل گذرواژهها، جزئیات پرداخت، پیامها، عکسها، و صدا و تصویر باشید."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"شروع"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"سرپرست فناوری اطلاعات آن را مسدود کرده است"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"«ضبط صفحهنمایش» بهدلیل خطمشی دستگاه غیرفعال است"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index abf52fef2ae1..f3b95de8c5d5 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Napauta näyttääksesi"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Virhe näyttötallenteen tallentamisessa"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Koko näytön tilassa"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Sulje palkki pyyhkäisemällä alas ruudun ylälaidasta."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Selvä"</string> <string name="accessibility_back" msgid="6530104400086152611">"Takaisin"</string> <string name="accessibility_home" msgid="5430449841237966217">"Aloitus"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Valikko"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kun jaat, tallennat tai striimaat, Android saa pääsyn kaikkeen näytölläsi näkyvään tai laitteellasi toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kun jaat, tallennat tai striimaat, Android saa pääsyn kaikkeen sovelluksella näkyvään tai toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Aloita"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IT-järjestelmänvalvojasi estämä"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Kuvakaappaus on poistettu käytöstä laitekäytännön perusteella"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tyhjennä kaikki"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 4f94d1f2249a..8a74f8a7d1ff 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Touchez pour afficher"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Erreur d\'enregistrement de l\'écran"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Une erreur s\'est produite lors du démarrage de l\'enregistrement d\'écran"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Affichage plein écran"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Pour quitter, balayez vers le bas à partir du haut."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Précédent"</string> <string name="accessibility_home" msgid="5430449841237966217">"Domicile"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Lorsque vous partagez, enregistrez ou diffusez, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Lorsque vous partagez, enregistrez ou diffusez une application, Android a accès à tout ce qui est visible sur votre écran ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Commencer"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloquée par votre administrateur informatique"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"La fonctionnalité de capture d\'écran est désactivée par l\'application Device Policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 0ede09a263bb..5fe8f558d123 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Appuyez pour afficher"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Erreur lors de l\'enregistrement de l\'écran"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Erreur lors du démarrage de l\'enregistrement de l\'écran"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Affichage en plein écran"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Pour quitter, balayez l\'écran du haut vers le bas."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Retour"</string> <string name="accessibility_home" msgid="5430449841237966217">"Accueil"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Lorsque vous partagez, enregistrez ou castez, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages, photos et contenus audio et vidéo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Lorsque vous partagez, enregistrez ou castez une appli, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages et contenus audio et vidéo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Commencer"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloqué par votre administrateur informatique"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"La capture d\'écran est désactivée conformément aux règles relatives à l\'appareil"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 144675563f77..804aeca026af 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Toca para ver o contido"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Produciuse un erro ao gardar a gravación da pantalla"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Produciuse un erro ao iniciar a gravación da pantalla"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Vendo pantalla completa"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Para saír, pasa o dedo cara abaixo desde a parte superior."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Entendido"</string> <string name="accessibility_back" msgid="6530104400086152611">"Volver"</string> <string name="accessibility_home" msgid="5430449841237966217">"Inicio"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menú"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Cando compartes, gravas ou emites contido, Android ten acceso a todo o que se vexa na pantalla ou se reproduza no teu dispositivo. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Cando compartes, gravas ou emites unha aplicación, Android ten acceso a todo o que se vexa ou se reproduza nela. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Iniciar"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"O teu administrador de TI bloqueou esta aplicación"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A política do dispositivo desactivou a opción de capturar a pantalla"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todo"</string> @@ -1040,7 +1051,7 @@ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca para obter máis información"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Sen alarmas postas"</string> - <string name="accessibility_bouncer" msgid="5896923685673320070">"introducir bloqueo de pantalla"</string> + <string name="accessibility_bouncer" msgid="5896923685673320070">"introducir o bloqueo de pantalla"</string> <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impresión dixital"</string> <string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string> <string name="accessibility_enter_hint" msgid="2617864063504824834">"poñer o dispositivo"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 89390b14732f..cfd5a360c85d 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"જોવા માટે ટૅપ કરો"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"સ્ક્રીન રેકોર્ડિંગ સાચવવામાં ભૂલ આવી"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"સ્ક્રીનને રેકૉર્ડ કરવાનું શરૂ કરવામાં ભૂલ"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"પૂર્ણ સ્ક્રીન પર જુઓ"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"બહાર નીકળવા માટે, ટોચ પરથી નીચે સ્વાઇપ કરો."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"સમજાઈ ગયું"</string> <string name="accessibility_back" msgid="6530104400086152611">"પાછળ"</string> <string name="accessibility_home" msgid="5430449841237966217">"હોમ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"મેનુ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"જ્યારે તમે શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પર દેખાતી હોય કે તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી બધી વસ્તુનો ઍક્સેસ Android પાસે હોય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"જ્યારે તમે કોઈ ઍપ શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી બધી વસ્તુનો ઍક્સેસ Android પાસે હોય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"શરૂ કરો"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"તમારા IT ઍડમિન દ્વારા બ્લૉક કરાયેલી"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ડિવાઇસ પૉલિસી અનુસાર સ્ક્રીન કૅપ્ચર કરવાની સુવિધા બંધ કરવામાં આવી છે"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index fb017da39dee..194321af397e 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"देखने के लिए टैप करें"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"स्क्रीन रिकॉर्डिंग सेव करते समय गड़बड़ी हुई"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन को रिकॉर्ड करने में गड़बड़ी आ रही है"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"फ़ुल स्क्रीन मोड पर देखा जा रहा है"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"बाहर निकलने के लिए, सबसे ऊपर से नीचे की ओर स्वाइप करें."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ठीक है"</string> <string name="accessibility_back" msgid="6530104400086152611">"वापस जाएं"</string> <string name="accessibility_home" msgid="5430449841237966217">"होम"</string> <string name="accessibility_menu" msgid="2701163794470513040">"मेन्यू"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"शेयर, रिकॉर्ड या कास्ट करते समय, Android के पास स्क्रीन पर दिख रहे कॉन्टेंट या डिवाइस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, और डिवाइस पर चल रहे ऑडियो और वीडियो को लेकर सावधानी बरतें."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"किसी ऐप्लिकेशन को शेयर, रिकॉर्ड या कास्ट करते समय, Android के पास उस ऐप्लिकेशन पर दिख रहे कॉन्टेंट या उस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, और डिवाइस पर चल रहे ऑडियो और वीडियो को लेकर सावधानी बरतें."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"शुरू करें"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"आपके आईटी एडमिन ने स्क्रीन कैप्चर करने की सुविधा पर रोक लगाई है"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"डिवाइस से जुड़ी नीति के तहत स्क्रीन कैप्चर करने की सुविधा बंद है"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"सभी को हटाएं"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index b7a7cdd1785c..7fbc100fc585 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Dodirnite za prikaz"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Pogreška prilikom spremanja snimke zaslona"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Gledanje preko cijelog zaslona"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Za izlaz prijeđite prstom od vrha prema dolje."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Shvaćam"</string> <string name="accessibility_back" msgid="6530104400086152611">"Natrag"</string> <string name="accessibility_home" msgid="5430449841237966217">"Početna"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Izbornik"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kad dijelite, snimate ili emitirate, Android ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kad dijelite, snimate ili emitirate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Pokreni"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokirao vaš IT administrator"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Snimanje zaslona onemogućeno je u skladu s pravilima za uređaje"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 6a96fccc6a1c..1c46c441a04f 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Koppintson a megtekintéshez"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Hiba történt a képernyőrögzítés mentése során"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Hiba a képernyőrögzítés indításakor"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Megtekintése teljes képernyőn"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Kilépéshez csúsztassa ujját fentről lefelé."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Értem"</string> <string name="accessibility_back" msgid="6530104400086152611">"Vissza"</string> <string name="accessibility_home" msgid="5430449841237966217">"Főoldal"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menü"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Amikor Ön megosztást, rögzítést vagy átküldést végez, az Android a képernyőn látható vagy az eszközön lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Amikor Ön megoszt, rögzít vagy átküld egy alkalmazást, az Android az adott alkalmazásban látható vagy lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Indítás"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Rendszergazda által letiltva"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A képernyőfelvételt eszközszabályzat tiltja"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Az összes törlése"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index d91b3dd24c28..afd8b66dc859 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Հպեք՝ դիտելու համար"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Չհաջողվեց պահել էկրանի տեսագրությունը"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Չհաջողվեց սկսել տեսագրումը"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Լիաէկրան դիտում"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Դուրս գալու համար վերևից սահահարվածեք դեպի ներքև:"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Պարզ է"</string> <string name="accessibility_back" msgid="6530104400086152611">"Հետ"</string> <string name="accessibility_home" msgid="5430449841237966217">"Տուն"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Ցանկ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Երբ դուք ցուցադրում, տեսագրում կամ հեռարձակում եք էկրանը, Android-ին հասանելի է լինում այն ամենը, ինչ տեսանելի է ձեր էկրանին և նվագարկվում է ձեր սարքում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Երբ դուք ցուցադրում, տեսագրում կամ հեռարձակում եք որևէ հավելվածի էկրանը, Android-ին հասանելի է լինում այն ամենը, ինչ ցուցադրվում է կամ նվագարկվում այդ հավելվածում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Սկսել"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Արգելափակվել է ձեր ՏՏ ադմինիստրատորի կողմից"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Էկրանի տեսագրումն անջատված է սարքի կանոնների համաձայն"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Մաքրել բոլորը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 550b04855ae8..f5564ba4b446 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Ketuk untuk melihat"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Terjadi error saat menyimpan rekaman layar"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Melihat layar penuh"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Untuk keluar, geser layar ke bawah dari atas."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Mengerti"</string> <string name="accessibility_back" msgid="6530104400086152611">"Kembali"</string> <string name="accessibility_home" msgid="5430449841237966217">"Utama"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Jika Anda membagikan, merekam, atau mentransmisikan, Android akan memiliki akses ke semua hal yang ditampilkan di layar atau yang diputar di perangkat Anda. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Jika Anda membagikan, merekam, atau mentransmisikan suatu aplikasi, Android akan memiliki akses ke semua hal yang ditampilkan atau yang diputar di aplikasi tersebut. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Mulai"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Diblokir oleh admin IT Anda"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Pengambilan screenshot dinonaktifkan oleh kebijakan perangkat"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hapus semua"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 86455c08931b..647d1c49af71 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Ýttu til að skoða"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Villa við að vista skjáupptöku"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Villa við að hefja upptöku skjás"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Notar allan skjáinn"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Strjúktu niður frá efri brún til að hætta."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Ég skil"</string> <string name="accessibility_back" msgid="6530104400086152611">"Til baka"</string> <string name="accessibility_home" msgid="5430449841237966217">"Heim"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Valmynd"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Þegar þú deilir, tekur upp eða varpar hefur Android aðgang að öllu sem sést á skjánum eða spilast í tækinu. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Þegar þú deilir, tekur upp eða varpar forriti hefur Android aðgang að öllu sem sést eða spilast í viðkomandi forriti. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Byrja"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Útilokað af kerfisstjóra"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Slökkt er á skjáupptöku í tækjareglum"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 17ec328856ae..3b60f427e211 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tocca per visualizzare"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Errore durante il salvataggio della registrazione dello schermo"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Errore durante l\'avvio della registrazione dello schermo"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visualizzazione a schermo intero"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Per uscire, scorri dall\'alto verso il basso."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Indietro"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Quando condividi, registri o trasmetti, Android ha accesso a qualsiasi elemento visibile sul tuo schermo o in riproduzione sul tuo dispositivo. Presta quindi attenzione a password, dettagli sui pagamenti, messaggi, foto, audio e video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Quando condividi, registri o trasmetti un\'app, Android ha accesso a qualsiasi elemento visualizzato o riprodotto sull\'app. Presta quindi attenzione a password, dettagli sui pagamenti, messaggi, foto, audio e video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Inizia"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloccata dall\'amministratore IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"L\'acquisizione schermo è disattivata dai criteri relativi ai dispositivi"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Cancella tutto"</string> @@ -510,14 +521,14 @@ <string name="stream_accessibility" msgid="3873610336741987152">"Accessibilità"</string> <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Attiva suoneria"</string> <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Attiva vibrazione"</string> - <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Disattiva suoneria"</string> + <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenzia"</string> <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tocca per riattivare l\'audio."</string> <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string> <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string> <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tocca per attivare la vibrazione."</string> <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tocca per disattivare l\'audio."</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tocca per cambiare la modalità della suoneria"</string> - <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"disattiva l\'audio"</string> + <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenzia"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string> <string name="volume_dialog_title" msgid="6502703403483577940">"Controlli del volume %s"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 5b317cbf9db7..121e5be22a2e 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"יש להקיש כדי להציג"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"שגיאה בשמירה של הקלטת המסך"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"צפייה במסך מלא"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"כדי לצאת, פשוט מחליקים אצבע מלמעלה למטה."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"הבנתי"</string> <string name="accessibility_back" msgid="6530104400086152611">"חזרה"</string> <string name="accessibility_home" msgid="5430449841237966217">"בית"</string> <string name="accessibility_menu" msgid="2701163794470513040">"תפריט"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"בזמן שיתוף, הקלטה או העברה (cast) תהיה ל-Android גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"בזמן שיתוף, הקלטה או העברה (cast) של אפליקציה, תהיה ל-Android גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"התחלה"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"האפשרות נחסמה על ידי אדמין ב-IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"צילום המסך מושבת בגלל מדיניות המכשיר"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכול"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 56a78e28d0e0..383d9f481952 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"タップすると表示されます"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"画面の録画の保存中にエラーが発生しました"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"画面の録画中にエラーが発生しました"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"全画面表示"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"終了するには、上から下にスワイプします。"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"戻る"</string> <string name="accessibility_home" msgid="5430449841237966217">"ホーム"</string> <string name="accessibility_menu" msgid="2701163794470513040">"メニュー"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"共有、録画、キャスト中は、画面に表示される内容やデバイスで再生される内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"アプリの共有、録画、キャスト中は、そのアプリで表示または再生される内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"開始"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IT 管理者によりブロックされました"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"デバイス ポリシーに基づき、画面のキャプチャが無効になりました"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"すべて消去"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index f19b6b634ea2..943b288558c6 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"შეეხეთ სანახავად"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ეკრანის ჩანაწერის შენახვისას შეცდომა მოხდა"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ეკრანის ჩაწერის დაწყებისას წარმოიქმნა შეცდომა"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"მიმდინარეობს სრულ ეკრანზე ნახვა"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"გასვლისთვის გადაფურცლეთ ზემოდან ქვემოთ."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"გასაგებია"</string> <string name="accessibility_back" msgid="6530104400086152611">"უკან"</string> <string name="accessibility_home" msgid="5430449841237966217">"საწყისი"</string> <string name="accessibility_menu" msgid="2701163794470513040">"მენიუ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"გაზიარებისას, ჩაწერისას ან ტრანსლირებისას, Android-ს წვდომა აქვს ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენს მოწყობილობაზე. ამიტომ იყავით ფრთხილად ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"აპის გაზიარებისას, ჩაწერისას ან ტრანსლირებისას, Android-ს წვდომა აქვს ყველაფერზე, რაც ჩანს ან იკვრება აპში. ამიტომ იყავით ფრთხილად ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"დაწყება"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"დაბლოკილია თქვენი IT-ადმინისტრატორის მიერ"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ეკრანის აღბეჭდვა გამორთულია მოწყობილობის წესების თანახმად"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ყველას გასუფთავება"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index c7d30e79286c..a80dcfbb936b 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Көру үшін түртіңіз."</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Экран жазбасын сақтау кезінде қате шықты."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Экрандағы бейнені жазу кезінде қате шықты."</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Толық экранда көру"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Шығу үшін жоғарыдан төмен қарай сырғытыңыз."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Түсінікті"</string> <string name="accessibility_back" msgid="6530104400086152611">"Артқа"</string> <string name="accessibility_home" msgid="5430449841237966217">"Үй"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Mәзір"</string> @@ -301,8 +304,8 @@ <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн шыққанға дейін"</string> <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string> <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> дейін"</string> - <string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Ұйқы уақытында"</string> - <string name="quick_settings_dark_mode_secondary_label_until_bedtime_ends" msgid="1790772410777123685">"Ұйқы уақыты аяқталғанға дейін"</string> + <string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Ұйқы режимінде"</string> + <string name="quick_settings_dark_mode_secondary_label_until_bedtime_ends" msgid="1790772410777123685">"Ұйқы режимі аяқталғанға дейін"</string> <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string> <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өшірулі"</string> <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC қосулы"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Бөлісу, жазу не трансляциялау кезінде Android жүйесі экраныңызда көрінетін не құрылғыңызда ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Қолданба экранын бөлісу, жазу не трансляциялау кезінде Android жүйесі онда көрінетін не ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Бастау"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Әкімшіңіз бөгеген"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Құрылғы саясатына байланысты экранды түсіру өшірілді."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Барлығын тазарту"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 375b79d5acf0..702b9cba0bb4 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ចុចដើម្បីមើល"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"មានបញ្ហាក្នុងការរក្សាទុកការថតវីដេអូអេក្រង់"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"មានបញ្ហាក្នុងការចាប់ផ្ដើមថតអេក្រង់"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"កំពុងមើលពេញអេក្រង់"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ដើម្បីចាកចេញ សូមអូសពីលើចុះក្រោម។"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"យល់ហើយ"</string> <string name="accessibility_back" msgid="6530104400086152611">"ថយក្រោយ"</string> <string name="accessibility_home" msgid="5430449841237966217">"គេហទំព័រ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"ម៉ឺនុយ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬភ្ជាប់, Android មានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬចាក់នៅលើឧបករណ៍របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬភ្ជាប់កម្មវិធី, Android មានសិទ្ធិចូលប្រើអ្វីៗដែលបង្ហាញ ឬចាក់នៅលើកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ចាប់ផ្ដើម"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"បានទប់ស្កាត់ដោយអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នក"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ការថតអេក្រង់ត្រូវបានបិទដោយគោលការណ៍ឧបករណ៍"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាតទាំងអស់"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 437f40675feb..544af6a7c787 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೇವ್ ಮಾಡುವಾಗ ದೋಷ ಎದುರಾಗಿದೆ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ನಿರ್ಗಮಿಸಲು, ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ಅರ್ಥವಾಯಿತು"</string> <string name="accessibility_back" msgid="6530104400086152611">"ಹಿಂದೆ"</string> <string name="accessibility_home" msgid="5430449841237966217">"ಮುಖಪುಟ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"ಮೆನು"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"ನೀವು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುತ್ತಿರುವಾಗ ಅಥವಾ ಕ್ಯಾಸ್ಟ್ ಮಾಡುತ್ತಿರುವಾಗ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಕಾಣಿಸುವ ಅಥವಾ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ Android ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುತ್ತಿರುವಾಗ ಅಥವಾ ಕ್ಯಾಸ್ಟ್ ಮಾಡುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್ನಲ್ಲಿ ತೋರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ Android ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ಪ್ರಾರಂಭಿಸಿ"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ನಿರ್ಬಂಧಿಸಿದ್ದಾರೆ"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ಸಾಧನ ನೀತಿಯಿಂದ ಸ್ಕ್ರೀನ್ ಕ್ಯಾಪ್ಚರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 991695144024..bd58c0fed370 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"탭하여 보기"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"화면 녹화 저장 중에 오류가 발생했습니다."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"화면 녹화 시작 중 오류 발생"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"전체 화면 모드"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"종료하려면 위에서 아래로 스와이프합니다."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"확인"</string> <string name="accessibility_back" msgid="6530104400086152611">"뒤로"</string> <string name="accessibility_home" msgid="5430449841237966217">"홈"</string> <string name="accessibility_menu" msgid="2701163794470513040">"메뉴"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"공유, 녹화 또는 전송 중에 Android가 화면에 표시되거나 기기에서 재생되는 모든 항목에 액세스할 수 있습니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"앱을 공유, 녹화 또는 전송할 때는 Android가 해당 앱에 표시되거나 재생되는 모든 항목에 액세스할 수 있으므로 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"시작"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IT 관리자에 의해 차단됨"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"기기 정책에 의해 화면 캡처가 사용 중지되었습니다."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"모두 지우기"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index aaec2cdb6bc3..054aa2ea8e34 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Көрүү үчүн таптаңыз"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Экран тартылган жок"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Экранды жаздырууну баштоодо ката кетти"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Толук экран режимин көрүү"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Чыгуу үчүн экранды ылдый сүрүп коюңуз."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Түшүндүм"</string> <string name="accessibility_back" msgid="6530104400086152611">"Артка"</string> <string name="accessibility_home" msgid="5430449841237966217">"Үйгө"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Меню"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Бөлүшүп, жаздырып же тышкы экранга чыгарып жатканда Android экраныңыздагы бардык маалыматты же түзмөктө ойнотулуп жаткан нерселерди көрө алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Колдонмону бөлүшүп, жаздырып же тышкы экранга чыгарганда Android ал колдонмодо көрсөтүлүп жана ойнотулуп жаткан нерселерди көрө алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Баштоо"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IT администраторуңуз бөгөттөп койгон"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Түзмөк саясаты экрандагыны тартып алууну өчүрүп койгон"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 0306fc91d85e..66bd9e3636fc 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ແຕະເພື່ອເບິ່ງ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ເກີດຂໍ້ຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ເກີດຄວາມຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ກຳລັງເບິ່ງເຕັມຈໍ"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ເພື່ອອອກ, ໃຫ້ປັດລົງຈາກເທິງສຸດ."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ເຂົ້າໃຈແລ້ວ"</string> <string name="accessibility_back" msgid="6530104400086152611">"ກັບຄືນ"</string> <string name="accessibility_home" msgid="5430449841237966217">"ໜ້າທຳອິດ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"ເມນູ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"ເມື່ອທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານ, Android ຈະມີສິດເຂົ້າເຖິງທຸກສິ່ງທີ່ປາກົດຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"ເມື່ອທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານແອັບ, Android ຈະມີສິດເຂົ້າເຖິງທຸກສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ແອັບດັ່ງກ່າວ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ເລີ່ມ"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ຖືກບລັອກໄວ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານ"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ການຖ່າຍຮູບໜ້າຈໍຖືກປິດການນຳໃຊ້ໄວ້ໂດຍນະໂຍບາຍອຸປະກອນ"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ລຶບລ້າງທັງໝົດ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 8548a24ec73d..c93506f98aa5 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Palieskite, kad peržiūrėtumėte"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Išsaugant ekrano įrašą įvyko klaida"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Pradedant ekrano vaizdo įrašymą iškilo problema"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Peržiūrima viso ekrano režimu"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Jei norite išeiti, perbraukite žemyn iš viršaus."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Supratau"</string> <string name="accessibility_back" msgid="6530104400086152611">"Atgal"</string> <string name="accessibility_home" msgid="5430449841237966217">"Pagrindinis"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Meniu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kai bendrinate, įrašote ar perduodate turinį, „Android“ gali pasiekti viską, kas rodoma ekrane ar leidžiama įrenginyje. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kai bendrinate, įrašote ar perduodate programą, „Android“ gali pasiekti viską, kas rodoma ar leidžiama programoje. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Pradėti"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Užblokavo jūsų IT administratorius"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ekrano fiksavimo funkcija išjungta vadovaujantis įrenginio politika"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Viską išvalyti"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 79f73b681ab8..dcd54c499c5f 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Pieskarieties, lai skatītu"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Saglabājot ekrāna ierakstu, radās kļūda."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Sākot ierakstīt ekrāna saturu, radās kļūda."</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Skatīšanās pilnekrāna režīmā"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Lai izietu, no augšdaļas velciet lejup."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Labi"</string> <string name="accessibility_back" msgid="6530104400086152611">"Atpakaļ"</string> <string name="accessibility_home" msgid="5430449841237966217">"Sākums"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Izvēlne"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kopīgošanas, ierakstīšanas vai apraides laikā Android var piekļūt visam, kas tiek rādīts jūsu ekrānā vai atskaņots jūsu ierīcē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Lietotnes kopīgošanas, ierakstīšanas vai apraides laikā Android var piekļūt visam, kas tiek rādīts vai atskaņots attiecīgajā lietotnē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Sākt"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloķējis jūsu IT administrators"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ierīces politika ir atspējojusi ekrānuzņēmumu izveidi"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Dzēst visu"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index b8829c6ccf58..e83bf8165ffd 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Допрете за прегледување"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Грешка при зачувувањето на снимката од екранот"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при почетокот на снимањето на екранот"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Се прикажува на цел екран"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"За да излезете, повлечете одозгора надолу."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Сфатив"</string> <string name="accessibility_back" msgid="6530104400086152611">"Назад"</string> <string name="accessibility_home" msgid="5430449841237966217">"Почетна страница"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Мени"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Кога споделувате, снимате или емитувате, Android има пристап до сѐ што е видливо на вашиот екран или пуштено на вашиот уред. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Кога споделувате, снимате или емитувате апликација, Android има пристап до сѐ што се прикажува или пушта на таа апликација. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Започни"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Блокирано од IT-администраторот"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Снимањето на екранот е оневозможено со правила на уредот"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index f8c14e6d3b60..c8fbde84853b 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"കാണാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"സ്ക്രീൻ റെക്കോർഡിംഗ് സംരക്ഷിക്കുന്നതിൽ പിശക്"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"സ്ക്രീൻ റെക്കോർഡിംഗ് ആരംഭിക്കുന്നതിൽ പിശക്"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"പൂർണ്ണ സ്ക്രീനിൽ കാണുന്നു"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"പുറത്തുകടക്കാൻ, മുകളിൽ നിന്ന് താഴോട്ട് സ്വൈപ്പ് ചെയ്യുക."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"മനസ്സിലായി"</string> <string name="accessibility_back" msgid="6530104400086152611">"മടങ്ങുക"</string> <string name="accessibility_home" msgid="5430449841237966217">"ഹോം"</string> <string name="accessibility_menu" msgid="2701163794470513040">"മെനു"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"പങ്കിടുമ്പോൾ, റെക്കോർഡ് ചെയ്യുമ്പോൾ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യുമ്പോൾ, Android-ന് നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ഉപകരണത്തിൽ പ്ലേ ചെയ്യുന്നതോ ആയ ഏത് കാര്യത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ പാസ്വേഡുകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"ഒരു ആപ്പ് പങ്കിടുമ്പോൾ, റെക്കോർഡ് ചെയ്യുമ്പോൾ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യുമ്പോൾ, Android-ന് ആ ആപ്പിൽ കാണിക്കുന്ന അല്ലെങ്കിൽ പ്ലേ ചെയ്യുന്ന എല്ലാത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ പാസ്വേഡുകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ആരംഭിക്കുക"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"നിങ്ങളുടെ ഐടി അഡ്മിൻ ബ്ലോക്ക് ചെയ്തു"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ഉപകരണ നയം, സ്ക്രീൻ ക്യാപ്ചർ ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കി"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"എല്ലാം മായ്ക്കുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index ceb87821b4a7..15745ff24304 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Харахын тулд товшино уу"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Дэлгэцийн бичлэгийг хадгалахад алдаа гарлаа"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Дэлгэцийн бичлэгийг эхлүүлэхэд алдаа гарлаа"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Бүтэн дэлгэцээр үзэж байна"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Гарахаар бол дээрээс нь доош нь чирнэ үү."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Ойлголоо"</string> <string name="accessibility_back" msgid="6530104400086152611">"Буцах"</string> <string name="accessibility_home" msgid="5430449841237966217">"Гэрийн"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Цэс"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Таныг хуваалцаж, бичлэг хийж эсвэл дамжуулж байх үед Android таны дэлгэцэд харуулсан эсвэл төхөөрөмжид тань тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио болон видео зэрэг зүйлд болгоомжтой хандаарай."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Таныг хуваалцаж, бичлэг хийж эсвэл дамжуулж байх үед Android тухайн аппад харуулсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио болон видео зэрэг бусад зүйлд болгоомжтой хандаарай."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Эхлүүлэх"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Таны IT админ блоклосон"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Төхөөрөмжийн бодлогоор дэлгэцийн зураг авахыг идэвхгүй болгосон"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index ba45d533d614..a52d217871c6 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"पाहण्यासाठी टॅप करा"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"स्क्रीन रेकॉर्डिंग सेव्ह करताना एरर आली"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन रेकॉर्डिंग सुरू करताना एरर आली"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"पूर्ण स्क्रीनवर पाहत आहात"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"समजले"</string> <string name="accessibility_back" msgid="6530104400086152611">"मागे"</string> <string name="accessibility_home" msgid="5430449841237966217">"होम"</string> <string name="accessibility_menu" msgid="2701163794470513040">"मेनू"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"तुम्ही शेअर, रेकॉर्ड किंवा कास्ट करत असताना, Android ला तुमच्या स्क्रीनवर दाखवलेल्या किंवा डिव्हाइसवर प्ले केलेल्या कोणत्याही गोष्टीचा अॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"तुम्ही एखादे अॅप शेअर, रेकॉर्ड किंवा कास्ट करत असताना, Android ला त्या अॅपवर दाखवलेल्या किंवा प्ले केलेल्या कोणत्याही गोष्टीचा अॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"सुरुवात करा"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"तुमच्या आयटी ॲडमिनने ब्लॉक केले आहे"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"डिव्हाइस धोरणाने स्क्रीन कॅप्चर करणे बंद केले आहे"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index e28ea016af97..3da42a54c497 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Ketik untuk lihat"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Ralat semasa menyimpan rakaman skrin"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ralat semasa memulakan rakaman skrin"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Melihat skrin penuh"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Untuk keluar, leret ke bawah dari bahagian atas."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Kembali"</string> <string name="accessibility_home" msgid="5430449841237966217">"Rumah"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Apabila anda membuat perkongsian, rakaman atau penghantaran, Android boleh mengakses apa-apa sahaja yang boleh dilihat pada skrin anda atau dimainkan pada peranti anda. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Apabila anda berkongsi, merakam atau menghantar apl, Android boleh mengakses apa-apa sahaja yang ditunjukan atau dimainkan pada apl tersebut. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Mula"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Disekat oleh pentadbir IT anda"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Tangkapan skrin dilumpuhkan oleh dasar peranti"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Kosongkan semua"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 5bcd5a09efb5..c258862513e3 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ကြည့်ရှုရန် တို့ပါ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ဖန်သားပြင်ရိုက်ကူးမှုကို သိမ်းရာတွင် အမှားရှိသည်"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ဖန်သားပြင် ရိုက်ကူးမှု စတင်ရာတွင် အမှားအယွင်းရှိနေသည်"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ဖန်သားပြင်အပြည့် ကြည့်နေသည်"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ထွက်ရန် အပေါ်မှ အောက်သို့ ပွတ်ဆွဲပါ။"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"နားလည်ပြီ"</string> <string name="accessibility_back" msgid="6530104400086152611">"နောက်သို့"</string> <string name="accessibility_home" msgid="5430449841237966217">"ပင်မစာမျက်နှာ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"မီနူး"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"မျှဝေ၊ ရုပ်သံဖမ်း (သို့) ကာစ်လုပ်သည့်အခါ Android သည် သင့်ဖန်သားပြင်တွင် မြင်နိုင်သည့် (သို့) သင့်စက်တွင် ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"အက်ပ်တစ်ခုဖြင့် မျှဝေ၊ ရုပ်သံဖမ်း (သို့) ကာစ်လုပ်သည့်အခါ Android သည် ယင်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့အရာများကို ဂရုစိုက်ပါ။"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"စတင်ရန်"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"သင်၏ IT စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ကိရိယာ မူဝါဒက ဖန်သားပြင်ပုံဖမ်းခြင်းကို ပိတ်ထားသည်"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံးရှင်းရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 755ee81a4d7a..9277d523f145 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Trykk for å se"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Feil ved lagring av skjermopptaket"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visning i fullskjerm"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Sveip ned fra toppen for å avslutte."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Skjønner"</string> <string name="accessibility_back" msgid="6530104400086152611">"Tilbake"</string> <string name="accessibility_home" msgid="5430449841237966217">"Startside"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Meny"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Når du deler, tar opp eller caster noe, har Android tilgang til alt som vises på skjermen eller spilles av på enheten. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Når du deler, tar opp eller caster en app, har Android tilgang til alt som vises eller spilles av i den aktuelle appen. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Begynn"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokkert av IT-administratoren"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Skjermdumper er deaktivert av enhetsinnstillingene"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Fjern alt"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index d1445e1e9c16..9f9bf85b25f7 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"हेर्नका लागि ट्याप गर्नुहोस्"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"स्क्रिन रेकर्डिङ सेभ गर्ने क्रममा त्रुटि भयो"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रिन रेकर्ड गर्न थाल्ने क्रममा त्रुटि भयो"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"पूरा पर्दा हेर्दै"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"बाहिर निस्कन, माथिबाट तल स्वाइप गर्नुहोस्।"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"बुझेँ"</string> <string name="accessibility_back" msgid="6530104400086152611">"पछाडि"</string> <string name="accessibility_home" msgid="5430449841237966217">"गृह"</string> <string name="accessibility_menu" msgid="2701163794470513040">"मेनु"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"तपाईंले सेयर गर्दा, रेकर्ड गर्दा वा कास्ट गर्दा Android ले तपाईंको स्क्रिनमा देखिने वा डिभाइसमा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"तपाईंले कुनै एप सेयर गर्दा, रेकर्ड गर्दा वा कास्ट गर्दा Android ले उक्त एपमा देखाइने वा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"सुरु गर्नुहोस्"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"तपाईंका IT एड्मिनले ब्लक गर्नुभएको छ"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"डिभाइसको नीतिका कारण स्क्रिन क्याप्चर गर्ने सुविधा अफ गरिएको छ"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"सबै हटाउनुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 932889b8ba77..5c8ba847e906 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tik om te bekijken"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Fout bij opslaan van schermopname"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Fout bij starten van schermopname"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Volledig scherm wordt getoond"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Swipe omlaag vanaf de bovenkant van het scherm om af te sluiten."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Terug"</string> <string name="accessibility_home" msgid="5430449841237966217">"Startscherm"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Als je deelt, opneemt of cast, heeft Android toegang tot alles dat zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Als je deelt, opneemt of cast, heeft Android toegang tot alles dat wordt getoond of afgespeeld in die app. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Starten"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Geblokkeerd door je IT-beheerder"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Schermopname staat uit vanwege apparaatbeleid"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 8061fd6ae217..e41e7c21e616 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ସ୍କ୍ରିନ ରେକର୍ଡିଂ ସେଭ କରିବାରେ ତ୍ରୁଟି"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନରେ ଦେଖିବା"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ବାହାରି ଯିବା ପାଇଁ, ଶୀର୍ଷରୁ ତଳକୁ ସ୍ୱାଇପ କରନ୍ତୁ।"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ବୁଝିଗଲି"</string> <string name="accessibility_back" msgid="6530104400086152611">"ଫେରନ୍ତୁ"</string> <string name="accessibility_home" msgid="5430449841237966217">"ହୋମ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"ମେନୁ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"ଆପଣ ସେୟାର, ରେକର୍ଡ କିମ୍ବା କାଷ୍ଟ କରିବା ସମୟରେ, ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ଆପଣଙ୍କ ଡିଭାଇସରେ ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ Androidର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"ଆପଣ ଏକ ଆପ ସେୟାର, ରେକର୍ଡ କିମ୍ବା କାଷ୍ଟ କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ Androidର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ଆରମ୍ଭ କରନ୍ତୁ"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ଦ୍ୱାରା ବ୍ଲକ କରାଯାଇଛି"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ଡିଭାଇସ ନୀତି ଦ୍ୱାରା ସ୍କ୍ରିନ କେପଚରିଂକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ସବୁ ଖାଲି କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 0f3ef6af3a77..cc6377558dae 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋ ਗਈ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋਈ"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ਪੂਰੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦੇਖੋ"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ਬਾਹਰ ਜਾਣ ਲਈ, ਉਪਰੋਂ ਹੇਠਾਂ ਸਵਾਈਪ ਕਰੋ।"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ਸਮਝ ਲਿਆ"</string> <string name="accessibility_back" msgid="6530104400086152611">"ਪਿੱਛੇ"</string> <string name="accessibility_home" msgid="5430449841237966217">"ਘਰ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"ਮੀਨੂ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਂਝਾ ਕਰਨ, ਰਿਕਾਰਡ ਕਰਨ, ਜਾਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, Android ਕੋਲ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਦੀ ਜਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਂਝਾ ਕਰਨ, ਰਿਕਾਰਡ ਕਰਨ, ਜਾਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, Android ਕੋਲ ਉਸ ਐਪ \'ਤੇ ਦਿਖਾਈ ਗਈ ਜਾਂ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਸੰਬੰਧੀ ਸਾਵਧਾਨ ਰਹੋ।"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ਸ਼ੁਰੂ ਕਰੋ"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ਡੀਵਾਈਸ ਨੀਤੀ ਦੇ ਕਾਰਨ ਸਕ੍ਰੀਨ ਕੈਪਚਰ ਕਰਨਾ ਬੰਦ ਹੈ"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 757ffcd338c5..21018f9976cb 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Kliknij, aby wyświetlić"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Podczas zapisywania nagrania ekranu wystąpił błąd"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Błąd podczas rozpoczynania rejestracji zawartości ekranu"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Włączony pełny ekran"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Aby wyjść, przesuń palcem z góry na dół."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Wróć"</string> <string name="accessibility_home" msgid="5430449841237966217">"Ekran główny"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Podczas udostępniania, nagrywania lub przesyłania treści Android ma dostęp do wszystkiego, co jest widoczne na ekranie lub odtwarzane na urządzeniu. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Podczas udostępniania, nagrywania lub przesyłania treści Android ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Rozpocznij"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Zablokowane przez administratora IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Zrzuty ekranu są wyłączone zgodnie z zasadami dotyczącymi urządzeń"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 4ee6bd2175b3..82015ea8136a 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Toque para ver"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Erro ao salvar a gravação da tela"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visualização em tela cheia"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Para sair, deslize de cima para baixo."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Entendi"</string> <string name="accessibility_back" msgid="6530104400086152611">"Voltar"</string> <string name="accessibility_home" msgid="5430449841237966217">"Página inicial"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Quando você compartilha, grava ou transmite a tela, o Android tem acesso a todas as informações visíveis nela ou reproduzidas no dispositivo. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Quando você compartilha, grava ou transmite um app, o Android tem acesso a todas as informações visíveis ou reproduzidas nele. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Início"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Ação bloqueada pelo administrador de TI"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A captura de tela foi desativada pela política do dispositivo"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Remover tudo"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index f16b0272114b..45853b9923d4 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Toque para ver"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Erro ao guardar a gravação de ecrã"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visualização de ecrã inteiro"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Para sair, deslize rapidamente para baixo a partir da parte superior."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Anterior"</string> <string name="accessibility_home" msgid="5430449841237966217">"Página inicial"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,10 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Quando está a partilhar, gravar ou transmitir conteúdo, o Android tem acesso a tudo o que está visível no seu ecrã ou é reproduzido no seu dispositivo. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Quando está a partilhar, gravar ou transmitir uma app, o Android tem acesso a tudo o que é apresentado ou reproduzido nessa app. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Iniciar"</string> + <string name="media_projection_task_switcher_text" msgid="590885489897412359">"A partilha é pausada quando muda de app"</string> + <string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Partilhar antes esta app"</string> + <string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Voltar"</string> + <string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Mudança de app"</string> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloqueado pelo administrador de TI"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A captura de ecrã está desativada pela política do dispositivo"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 4ee6bd2175b3..82015ea8136a 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Toque para ver"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Erro ao salvar a gravação da tela"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visualização em tela cheia"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Para sair, deslize de cima para baixo."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Entendi"</string> <string name="accessibility_back" msgid="6530104400086152611">"Voltar"</string> <string name="accessibility_home" msgid="5430449841237966217">"Página inicial"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Quando você compartilha, grava ou transmite a tela, o Android tem acesso a todas as informações visíveis nela ou reproduzidas no dispositivo. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Quando você compartilha, grava ou transmite um app, o Android tem acesso a todas as informações visíveis ou reproduzidas nele. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Início"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Ação bloqueada pelo administrador de TI"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"A captura de tela foi desativada pela política do dispositivo"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Remover tudo"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index e57eb5d6cb52..bc6a5fd6ada3 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Atinge pentru a afișa"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Eroare la salvarea înregistrării ecranului"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Eroare la începerea înregistrării ecranului"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Vizualizare pe ecran complet"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Pentru a ieși, glisează de sus în jos."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Înapoi"</string> <string name="accessibility_home" msgid="5430449841237966217">"Ecranul de pornire"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Meniu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Când permiți accesul, înregistrezi sau proiectezi, Android are acces la orice este vizibil pe ecran sau se redă pe dispozitiv. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Când permiți accesul, înregistrezi sau proiectezi o aplicație, Android are acces la orice se afișează pe ecran sau se redă în aplicație. Prin urmare, ai grijă cu informații cum ar fi parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Începe"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocată de administratorul IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Capturile de ecran sunt dezactivate de politica privind dispozitivele"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Șterge toate notificările"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 70f6e1598680..80b0d0fac060 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Нажмите, чтобы посмотреть."</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Не удалось сохранить запись видео с экрана."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Полноэкранный режим"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Чтобы выйти, проведите по экрану сверху вниз."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"ОК"</string> <string name="accessibility_back" msgid="6530104400086152611">"Назад"</string> <string name="accessibility_home" msgid="5430449841237966217">"Главный экран"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Меню"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Когда вы демонстрируете, транслируете экран или записываете видео с него, система Android получает доступ ко всему, что видно или воспроизводится на устройстве. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Когда вы демонстрируете, записываете или транслируете экран приложения, система Android получает доступ ко всему, что видно или воспроизводится в нем. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Начать"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Заблокировано вашим администратором"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Запись экрана отключена в соответствии с правилами для устройства."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистить все"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index b4dc0f27cfe2..8989b7ef0b90 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"බැලීමට තට්ටු කරන්න"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"තිර පටිගත කිරීම සුරැකීමේ දෝෂයකි"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"තිර පටිගත කිරීම ආරම්භ කිරීමේ දෝෂයකි"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"මුළු තිරය බලමින්"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"වැටහුණි"</string> <string name="accessibility_back" msgid="6530104400086152611">"ආපසු"</string> <string name="accessibility_home" msgid="5430449841237966217">"මුල් පිටුව"</string> <string name="accessibility_menu" msgid="2701163794470513040">"මෙනුව"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"ඔබ බෙදා ගන්නා විට, පටිගත කරන විට, හෝ විකාශය කරන විට, Android හට ඔබේ තිරයේ පෙනෙන හෝ ඔබේ උපාංගයේ වාදනය වන ඕනෑම දෙයකට ප්රවේශය ඇත. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්රව්ය සහ දෘශ්ය වැනි දේවල් පිළිබඳ ප්රවේශම් වන්න."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"ඔබ යෙදුමක් බෙදා ගන්නා විට, පටිගත කරන විට හෝ විකාශය කරන විට, Android හට එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයකට ප්රවේශය ඇත. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්රව්ය සහ දෘශ්ය වැනි දේවල් පිළිබඳ ප්රවේශම් වන්න."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"අරඹන්න"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ඔබේ IT පරිපාලක විසින් අවහිර කර ඇත"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"උපාංග ප්රතිපත්තිය මගින් තිර ග්රහණය කිරීම අබල කර ඇත"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"සියල්ල හිස් කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 802bd7a06123..e743d5604afc 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Zobrazte klepnutím"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Pri ukladaní nahrávky obrazovky sa vyskytla chyba"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Pri spustení nahrávania obrazovky sa vyskytla chyba"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Zobrazenie na celú obrazovku"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Ukončíte potiahnutím zhora nadol."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Dobre"</string> <string name="accessibility_back" msgid="6530104400086152611">"Späť"</string> <string name="accessibility_home" msgid="5430449841237966217">"Plocha"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Počas zdieľania, nahrávania alebo prenosu bude mať Android prístup k všetkému, čo sa zobrazuje na obrazovke alebo prehráva v zariadení. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Počas zdieľania, nahrávania alebo prenosu v aplikácii bude mať Android prístup k všetkému zobrazovanému alebo prehrávaného obsahu v danej aplikácii. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Začať"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokované vaším správcom IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Snímanie obrazovky je zakázané pravidlami pre zariadenie"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index a303e20ff5d4..90d62cb6b101 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Dotaknite se za ogled."</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Napaka pri shranjevanju posnetka zaslona"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Napaka pri začenjanju snemanja zaslona"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Vklopljen je celozaslonski način."</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Zaprete ga tako, da z vrha s prstom povlečete navzdol."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Razumem"</string> <string name="accessibility_back" msgid="6530104400086152611">"Nazaj"</string> <string name="accessibility_home" msgid="5430449841237966217">"Začetni zaslon"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Meni"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Pri deljenju, snemanju ali predvajanju ima Android dostop do vsega, kar je prikazano na zaslonu ali se predvaja v napravi. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Pri deljenju, snemanju ali predvajanju aplikacije ima Android dostop do vsega, kar je prikazano ali predvajano v tej aplikaciji, zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Začni"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blokiral skrbnik za IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Zajemanje zaslonske slike je onemogočil pravilnik za naprave."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši vse"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 4d0dcef5603b..3677bdee43b0 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Trokit për të parë"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Gabim gjatë ruajtjes së regjistrimit të ekranit"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Gabim gjatë nisjes së regjistrimit të ekranit"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Po shikon ekranin e plotë"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Për të dalë, rrëshqit nga lart poshtë."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"E kuptova"</string> <string name="accessibility_back" msgid="6530104400086152611">"Prapa"</string> <string name="accessibility_home" msgid="5430449841237966217">"Faqja bazë"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menyja"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kur ti ndan, regjistron ose transmeton, Android ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në pajisjen tënde. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kur ti ndan, regjistron ose transmeton një aplikacion, Android ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në atë aplikacion. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Nis"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"U bllokua nga administratori yt i teknologjisë së informacionit"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Regjistrimi i ekranit është çaktivizuar nga politika e pajisjes."</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Pastroji të gjitha"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 6227d5d8c06f..19d30658509d 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Додирните да бисте прегледали"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Грешка при чувању снимка екрана"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при покретању снимања екрана"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Приказује се цео екран"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Да бисте изашли, превуците надоле одозго."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Важи"</string> <string name="accessibility_back" msgid="6530104400086152611">"Назад"</string> <string name="accessibility_home" msgid="5430449841237966217">"Почетна"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Мени"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Када делите, снимате или пребацујете, Android има приступ комплетном садржају који је видљив на екрану или се пушта на уређају. Зато будите пажљиви са лозинкама, информацијама о плаћању, порукама, сликама и аудио и видео снимцима."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Када делите, снимате или пребацујете апликацију, Android има приступ комплетном садржају који је видљив или се пушта у тој апликацији. Зато будите пажљиви са лозинкама, информацијама о плаћању, порукама, сликама и аудио и видео снимцима."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Покрени"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Блокира ИТ администратор"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Снимање екрана је онемогућено смерницама за уређај"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 7cf096f43ca3..ae199e9ebb10 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Tryck för att visa"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Det gick inte att spara skärminspelningen"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Det gick inte att starta skärminspelningen"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Visar på fullskärm"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Svep nedåt från skärmens överkant för att avsluta."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Tillbaka"</string> <string name="accessibility_home" msgid="5430449841237966217">"Startsida"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Meny"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"När du delar, spelar in eller castar har Android åtkomst till allt som visas på skärmen eller spelas upp på enheten. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton och ljud och video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"När du delar, spelar in eller castar en app har Android åtkomst till allt som visas eller spelas upp i appen. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton och ljud och video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Börja"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blockeras av IT-administratören"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Skärminspelning är inaktiverat av enhetspolicyn"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Rensa alla"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 892d369e4330..abed50d4981c 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Gusa ili uangalie"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Hitilafu imetokea wakati wa kuhifadhi rekodi ya skrini"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Hitilafu imetokea wakati wa kuanza kurekodi skrini"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Unatazama kwenye skrini nzima"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Ili uondoke, telezesha kidole kutoka juu hadi chini."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Nimeelewa"</string> <string name="accessibility_back" msgid="6530104400086152611">"Nyuma"</string> <string name="accessibility_home" msgid="5430449841237966217">"Nyumbani"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menyu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Unaposhiriki, kurekodi au kutuma, Android inaweza kufikia kitu chochote kitakachoonekana kwenye skrini yako au kuchezwa kwenye kifaa chako. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha na sauti na video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Unaposhiriki, kurekodi au kutuma programu, Android inaweza kufikia kitu chochote kitakachoonekana au kuchezwa kwenye programu hiyo. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha na sauti na video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Anza"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Umezuiwa na msimamizi wako wa TEHAMA"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Mchakato wa kurekodi skrini umezimwa na sera ya kifaa"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Futa zote"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 3378e1345938..8d930a5f8d2a 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"பார்க்கத் தட்டவும்"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ஸ்கிரீன் ரெக்கார்டிங்கைச் சேமிப்பதில் பிழை ஏற்பட்டது"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"முழுத் திரையில் காட்டுகிறது"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"வெளியேற, மேலிருந்து கீழே ஸ்வைப் செய்யவும்"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"புரிந்தது"</string> <string name="accessibility_back" msgid="6530104400086152611">"பின்செல்"</string> <string name="accessibility_home" msgid="5430449841237966217">"முகப்பு"</string> <string name="accessibility_menu" msgid="2701163794470513040">"மெனு"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"நீங்கள் பகிரும்போதோ ரெக்கார்டு செய்யும்போதோ அலைபரப்பும்போதோ உங்கள் திரையில் காட்டப்படுகின்ற அல்லது சாதனத்தில் பிளே செய்யப்படுகின்ற அனைத்தையும் Android அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"நீங்கள் ஓர் ஆப்ஸைப் பகிரும்போதோ ரெக்கார்டு செய்யும்போதோ அலைபரப்பும்போதோ அந்த ஆப்ஸில் காட்டப்படுகின்ற அல்லது பிளே செய்யப்படுகின்ற அனைத்தையும் Android அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"தொடங்கு"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"உங்கள் IT நிர்வாகி தடுத்துள்ளார்"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"\'திரையைப் படமெடுத்தல்\' சாதனக் கொள்கையின்படி முடக்கப்பட்டுள்ளது"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"எல்லாவற்றையும் அழி"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 9e5054851af8..f90a43546a90 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"చూడటానికి ట్యాప్ చేయండి"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"స్క్రీన్ రికార్డింగ్ను సేవ్ చేయడంలో ఎర్రర్ ఏర్పడింది"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"ఫుల్ స్క్రీన్లో చూస్తున్నారు"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"నిష్క్రమించడానికి, పై నుండి కిందికి స్వైప్ చేయండి."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"సరే"</string> <string name="accessibility_back" msgid="6530104400086152611">"వెనుకకు"</string> <string name="accessibility_home" msgid="5430449841237966217">"హోమ్"</string> <string name="accessibility_menu" msgid="2701163794470513040">"మెనూ"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"మీరు షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్పై కనిపించే దేనికైనా లేదా మీ పరికరంలో ప్లే అయిన దేనికైనా Androidకు యాక్సెస్ ఉంటుంది. కాబట్టి పాస్వర్డ్లు, పేమెంట్ వివరాలు, మెసేజ్లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"మీరు ఏదైనా యాప్ను షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, ఆ యాప్లో చూపబడిన దేనికైనా లేదా ప్లే అయిన దేనికైనా Androidకు యాక్సెస్ ఉంటుంది. కాబట్టి పాస్వర్డ్లు, పేమెంట్ వివరాలు, మెసేజ్లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ప్రారంభించండి"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"మీ IT అడ్మిన్ ద్వారా బ్లాక్ చేయబడింది"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"పరికర పాలసీ ద్వారా స్క్రీన్ క్యాప్చర్ చేయడం డిజేబుల్ చేయబడింది"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"అన్నీ క్లియర్ చేయండి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 554324a17824..804379210885 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"แตะเพื่อดู"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"เกิดข้อผิดพลาดในการบันทึกหน้าจอ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"กำลังดูแบบเต็มหน้าจอ"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"หากต้องการออก ให้เลื่อนลงจากด้านบน"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"รับทราบ"</string> <string name="accessibility_back" msgid="6530104400086152611">"กลับ"</string> <string name="accessibility_home" msgid="5430449841237966217">"หน้าแรก"</string> <string name="accessibility_menu" msgid="2701163794470513040">"เมนู"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"เมื่อกำลังแชร์ บันทึก หรือแคสต์ Android จะมีสิทธิ์เข้าถึงทุกสิ่งที่ปรากฏบนหน้าจอหรือเล่นอยู่ในอุปกรณ์ ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"เมื่อกำลังแชร์ บันทึก หรือแคสต์แอป Android จะมีสิทธิ์เข้าถึงทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"เริ่ม"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ผู้ดูแลระบบไอทีบล็อกไว้"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"การจับภาพหน้าจอปิดใช้โดยนโยบายด้านอุปกรณ์"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ล้างทั้งหมด"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 2c632ec496d7..835c86438df9 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"I-tap para tingnan"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Nagka-error sa pag-save ng recording ng screen"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Nagkaroon ng error sa pagsisimula ng pag-record ng screen"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Panonood sa full screen"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Upang lumabas, mag-swipe mula sa itaas pababa."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Nakuha ko"</string> <string name="accessibility_back" msgid="6530104400086152611">"Bumalik"</string> <string name="accessibility_home" msgid="5430449841237966217">"Home"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Kapag nagbabahagi, nagre-record, o nagka-cast ka, may access ang Android sa kahit anong nakikita sa iyong screen o pine-play sa device mo. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Kapag nagbabahagi, nagre-record, o nagka-cast ka ng app, may access ang Android sa kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Simulan"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Na-block ng iyong IT admin"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Naka-disable ang pag-screen capture ayon sa patakaran ng device"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"I-clear lahat"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 84307715df44..3f05efa76bda 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Görüntülemek için dokunun"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Ekran kaydı saklanırken hata oluştu"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ekran kaydı başlatılırken hata oluştu"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Tam ekran olarak görüntüleme"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Çıkmak için yukarıdan aşağıya doğru hızlıca kaydırın."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Anladım"</string> <string name="accessibility_back" msgid="6530104400086152611">"Geri"</string> <string name="accessibility_home" msgid="5430449841237966217">"Ana sayfa"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menü"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Paylaşma, kaydetme veya yayınlama özelliğini kullandığınızda Android, ekranınızda gösterilen veya cihazınızda oynatılan her şeye erişebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Bir uygulamayı paylaştığınızda, kaydettiğinizde veya yayınladığınızda Android, söz konusu uygulamada gösterilen veya oynatılan her şeye erişebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Başlat"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"BT yöneticiniz tarafından engellendi"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ekran görüntüsü alma, cihaz politikası tarafından devre dışı bırakıldı"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tümünü temizle"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index b3ee948da161..d4b9c345bb29 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Натисніть, щоб переглянути"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Не вдалося зберегти запис відео з екрана"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Не вдалося почати запис екрана"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Перегляд на весь екран"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Щоб вийти, проведіть пальцем зверху вниз."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Назад"</string> <string name="accessibility_home" msgid="5430449841237966217">"Головна"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Меню"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Коли ви показуєте, записуєте або транслюєте екран, ОС Android отримує доступ до всього, що відображається на ньому чи відтворюється на пристрої. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Коли ви показуєте, записуєте або транслюєте додаток, ОС Android отримує доступ до всього, що відображається або відтворюється в ньому. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Почати"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Заблоковано адміністратором"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Запис екрана вимкнено згідно з правилами для пристрою"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистити все"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 3f47187fa3c1..acf1357d7cd8 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"دیکھنے کے لیے تھپتھپائیں"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"اسکرین ریکارڈنگ محفوظ کرنے میں خرابی"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"اسکرین ریکارڈنگ شروع کرنے میں خرابی"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"فُل اسکرین میں دیکھ رہے ہیں"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"باہر نکلنے کیلئے اوپر سے نیچے کی طرف سوائپ کریں۔"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"سمجھ آ گئی"</string> <string name="accessibility_back" msgid="6530104400086152611">"واپس جائیں"</string> <string name="accessibility_home" msgid="5430449841237966217">"ہوم"</string> <string name="accessibility_menu" msgid="2701163794470513040">"مینیو"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"جب آپ اشتراک، ریکارڈنگ یا کاسٹ کر رہے ہوتے ہیں تو Android کو آپ کی اسکرین پر دکھائی دینے والی یا آپ کے آلے پر چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"جب آپ اشتراک، ریکارڈنگ یا کسی ایپ کو کاسٹ کر رہے ہوتے ہیں تو Android کو اس ایپ پر دکھائی گئی یا چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"شروع کریں"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"آپ کے IT منتظم نے مسدود کر دیا"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"اسکرین کو کیپچر کرنا آلہ کی پالیسی کے ذریعے غیر فعال ہے"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 499eb1b435c6..2af9e922c843 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Koʻrish uchun bosing"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Ekran yozuvi saqlanmadi"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranni yozib olish boshlanmadi"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Butun ekranli rejim"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Chiqish uchun tepadan pastga torting."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Orqaga"</string> <string name="accessibility_home" msgid="5430449841237966217">"Uyga"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menyu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Ulashish, yozib olish va translatsiya qilish vaqtida Android ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Ilovani ulashish, yozib olish yoki translatsiya qilayotganingizda Android ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Boshlash"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"AT administratoringiz tomonidan bloklangan"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ekranni tasvirga olish qurilmadan foydalanish tartibi tomonidan faolsizlantirilgan"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 1d96b1ebfd64..791337dd60f6 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Nhấn để xem"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Có lỗi xảy ra khi lưu video ghi màn hình"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Lỗi khi bắt đầu ghi màn hình"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Xem toàn màn hình"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Để thoát, hãy vuốt từ trên cùng xuống dưới."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"OK"</string> <string name="accessibility_back" msgid="6530104400086152611">"Quay lại"</string> <string name="accessibility_home" msgid="5430449841237966217">"Trang chủ"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Khi bạn chia sẻ, ghi hoặc truyền, Android sẽ có quyền truy cập vào mọi nội dung xuất hiện trên màn hình hoặc phát trên thiết bị của bạn. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Khi bạn chia sẻ, ghi hoặc truyền ứng dụng, Android sẽ có quyền truy cập vào mọi nội dung xuất hiện hoặc phát trên ứng dụng đó. Vì vậy, hãy thận trọng để không làm lộ các thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Bắt đầu"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bị quản trị viên CNTT chặn"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Tính năng chụp ảnh màn hình đã bị tắt theo chính sách thiết bị"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Xóa tất cả"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 0699551dc81a..bc289ee4244b 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"点按即可查看"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"保存屏幕录制内容时出错"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"启动屏幕录制时出错"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"目前处于全屏模式"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"要退出,请从顶部向下滑动。"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"知道了"</string> <string name="accessibility_back" msgid="6530104400086152611">"返回"</string> <string name="accessibility_home" msgid="5430449841237966217">"主屏幕"</string> <string name="accessibility_menu" msgid="2701163794470513040">"菜单"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"在分享内容时,Android 可以访问屏幕上显示或设备中播放的所有内容。因此,请务必小心操作,谨防密码、付款信息、消息、照片、音频和视频等内容遭到泄露。"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"在分享、录制或投放内容时,Android 可以访问通过此应用显示或播放的所有内容。因此,请务必小心操作,谨防密码、付款信息、消息、照片、音频和视频等内容遭到泄露。"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"开始"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"已被 IT 管理员禁止"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"设备政策已停用屏幕截图功能"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 7160b5600274..8db6dbd8062d 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"輕按即可查看"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"儲存螢幕錄影時發生錯誤"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄影畫面時發生錯誤"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"開啟全螢幕"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"由頂部向下滑動即可退出。"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"知道了"</string> <string name="accessibility_back" msgid="6530104400086152611">"返回"</string> <string name="accessibility_home" msgid="5430449841237966217">"首頁"</string> <string name="accessibility_menu" msgid="2701163794470513040">"選單"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"當你分享、錄影或投放時,Android 可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"當你分享、錄影或投放應用程式時,Android 可存取顯示在該應用程式中顯示或播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"開始"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"已被你的 IT 管理員封鎖"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"螢幕截圖功能因裝置政策而停用"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 0deba3372662..9ba2aa9d8660 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"輕觸即可查看"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"儲存螢幕錄影內容時發生錯誤"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄製螢幕畫面時發生錯誤"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"以全螢幕檢視"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"如要退出,請從畫面頂端向下滑動。"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"知道了"</string> <string name="accessibility_back" msgid="6530104400086152611">"返回"</string> <string name="accessibility_home" msgid="5430449841237966217">"主畫面"</string> <string name="accessibility_menu" msgid="2701163794470513040">"選單"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"當你分享、錄製或投放內容時,Android 將可存取畫面上顯示的任何資訊或裝置播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"當你分享、錄製或投放內容時,Android 可存取應用程式中顯示的任何資訊或播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"開始"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"IT 管理員已封鎖這項操作"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"根據裝置政策規定,螢幕畫面擷取功能已停用"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index eb8ee45d3278..0e6bde25a1e6 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -118,6 +118,9 @@ <string name="screenrecord_save_text" msgid="3008973099800840163">"Thepha ukuze ubuke"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Iphutha lokulondoloza okokuqopha iskrini"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Iphutha lokuqala ukurekhoda isikrini"</string> + <string name="immersive_cling_title" msgid="8372056499315585941">"Ukubuka isikrini esigcwele"</string> + <string name="immersive_cling_description" msgid="6913958856085185775">"Ukuze uphume, swayiphela phansi kusuka phezulu."</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"Ngiyezwa"</string> <string name="accessibility_back" msgid="6530104400086152611">"Emuva"</string> <string name="accessibility_home" msgid="5430449841237966217">"Ekhaya"</string> <string name="accessibility_menu" msgid="2701163794470513040">"Imenyu"</string> @@ -412,6 +415,14 @@ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Uma wabelana, ukurekhoda, noma ukusakaza, i-Android inokufinyelela kunoma yini ebonakala esikrinini sakho noma okudlalwayo kudivayisi yakho. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yokukhokha, imilayezo, izithombe, nomsindo nevidiyo."</string> <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Uma wabelana, ukurekhoda, noma ukusakaza ku-app, i-Android inokufinyelela kunoma yini eboniswayo noma edlalwa kuleyo app. Ngakho-ke qaphela ngezinto ezfana namaphasiwedi, imininingwane yokukhokha, imilayezo, izithombe, nomsindo nevidiyo."</string> <string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Qala"</string> + <!-- no translation found for media_projection_task_switcher_text (590885489897412359) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_switch (8682258717291921123) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_action_back (5324164224147845282) --> + <skip /> + <!-- no translation found for media_projection_task_switcher_notification_channel (7613206306777814253) --> + <skip /> <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Kuvinjelwe ngumlawuli wakho we-IT"</string> <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Ukuthwebula isikrini kukhutshazwe yinqubomgomo yedivayisi"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Sula konke"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 47cd1e707557..3366f4f6d443 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -663,9 +663,6 @@ <dimen name="restricted_padlock_pading">4dp</dimen> - <!-- How far the expanded QS panel peeks from the header in collapsed state. --> - <dimen name="qs_peek_height">0dp</dimen> - <!-- Padding between subtitles and the following text in the QSFooter dialog --> <dimen name="qs_footer_dialog_subtitle_padding">20dp</dimen> diff --git a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml deleted file mode 100644 index b7d4b3aac079..000000000000 --- a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml +++ /dev/null @@ -1,101 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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 - --> -<ConstraintSet - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" > - - <Constraint - android:id="@+id/sizing_view" - android:layout_width="match_parent" - android:layout_height="@dimen/qs_media_session_height_collapsed" - /> - - <!-- Only the constraintBottom and marginBottom are different. The rest of the constraints are - the same as the constraints in media_recommendations_expanded.xml. But, due to how - ConstraintSets work, all the constraints need to be in the same place. So, the shared - constraints can't be put in the shared layout file media_smartspace_recommendations.xml and - the constraints are instead duplicated between here and media_recommendations_expanded.xml. - Ditto for the other cover containers. --> - <Constraint - android:id="@+id/media_cover1_container" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_cover2_container" - android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1.0" - app:layout_constraintVertical_bias="0.5" - /> - - <Constraint - android:id="@+id/media_title1" - android:visibility="gone" - /> - - <Constraint - android:id="@+id/media_subtitle1" - android:visibility="gone" - /> - - <Constraint - android:id="@+id/media_cover2_container" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toEndOf="@id/media_cover1_container" - app:layout_constraintEnd_toStartOf="@id/media_cover3_container" - android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" - app:layout_constraintVertical_bias="0.5" - /> - - <Constraint - android:id="@+id/media_title2" - android:visibility="gone" - /> - - <Constraint - android:id="@+id/media_subtitle2" - android:visibility="gone" - /> - - <Constraint - android:id="@+id/media_cover3_container" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toEndOf="@id/media_cover2_container" - app:layout_constraintEnd_toEndOf="parent" - android:layout_marginEnd="@dimen/qs_media_padding" - app:layout_constraintVertical_bias="0.5" - /> - - <Constraint - android:id="@+id/media_title3" - android:visibility="gone" - /> - - <Constraint - android:id="@+id/media_subtitle3" - android:visibility="gone" - /> - -</ConstraintSet> diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml deleted file mode 100644 index ce25a7d01bf7..000000000000 --- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml +++ /dev/null @@ -1,123 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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 - --> -<ConstraintSet - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - > - - <Constraint - android:id="@+id/sizing_view" - android:layout_width="match_parent" - android:layout_height="@dimen/qs_media_session_height_expanded" - /> - - <Constraint - android:id="@+id/media_cover1_container" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@+id/media_title1" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_cover2_container" - android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintHorizontal_bias="1.0" - app:layout_constraintVertical_bias="0.4" - /> - - <Constraint - android:id="@+id/media_title1" - style="@style/MediaPlayer.Recommendation.Text.Title" - app:layout_constraintStart_toStartOf="@+id/media_cover1_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover1_container" - app:layout_constraintTop_toBottomOf="@+id/media_cover1_container" - app:layout_constraintBottom_toTopOf="@+id/media_subtitle1" - /> - - <Constraint - android:id="@+id/media_subtitle1" - style="@style/MediaPlayer.Recommendation.Text.Subtitle" - app:layout_constraintStart_toStartOf="@+id/media_cover1_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover1_container" - app:layout_constraintTop_toBottomOf="@+id/media_title1" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" - /> - - <Constraint - android:id="@+id/media_cover2_container" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/media_title2" - app:layout_constraintStart_toEndOf="@id/media_cover1_container" - app:layout_constraintEnd_toStartOf="@id/media_cover3_container" - android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="0.4" - /> - - <Constraint - android:id="@+id/media_title2" - style="@style/MediaPlayer.Recommendation.Text.Title" - app:layout_constraintStart_toStartOf="@+id/media_cover2_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover2_container" - app:layout_constraintTop_toBottomOf="@+id/media_cover2_container" - app:layout_constraintBottom_toTopOf="@+id/media_subtitle2" - /> - - <Constraint - android:id="@+id/media_subtitle2" - style="@style/MediaPlayer.Recommendation.Text.Subtitle" - app:layout_constraintStart_toStartOf="@+id/media_cover2_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover2_container" - app:layout_constraintTop_toBottomOf="@+id/media_title2" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" - /> - - <Constraint - android:id="@+id/media_cover3_container" - style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/media_title3" - app:layout_constraintStart_toEndOf="@id/media_cover2_container" - app:layout_constraintEnd_toEndOf="parent" - android:layout_marginEnd="@dimen/qs_media_padding" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintVertical_bias="0.4" - /> - - <Constraint - android:id="@+id/media_title3" - style="@style/MediaPlayer.Recommendation.Text.Title" - app:layout_constraintStart_toStartOf="@+id/media_cover3_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover3_container" - app:layout_constraintTop_toBottomOf="@+id/media_cover3_container" - app:layout_constraintBottom_toTopOf="@+id/media_subtitle3" - /> - - <Constraint - android:id="@+id/media_subtitle3" - style="@style/MediaPlayer.Recommendation.Text.Subtitle" - app:layout_constraintStart_toStartOf="@+id/media_cover3_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover3_container" - app:layout_constraintTop_toBottomOf="@+id/media_title3" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" - /> - -</ConstraintSet> diff --git a/packages/SystemUI/res/xml/media_recommendations_view_collapsed.xml b/packages/SystemUI/res/xml/media_recommendations_collapsed.xml index d3be3c7de5ad..d3be3c7de5ad 100644 --- a/packages/SystemUI/res/xml/media_recommendations_view_collapsed.xml +++ b/packages/SystemUI/res/xml/media_recommendations_collapsed.xml diff --git a/packages/SystemUI/res/xml/media_recommendations_view_expanded.xml b/packages/SystemUI/res/xml/media_recommendations_expanded.xml index 88c70552e9e8..88c70552e9e8 100644 --- a/packages/SystemUI/res/xml/media_recommendations_view_expanded.xml +++ b/packages/SystemUI/res/xml/media_recommendations_expanded.xml diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt index 50e5466d0325..1cb8e43cf2c8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt @@ -12,12 +12,9 @@ class KeyguardClockFrame( ) : FrameLayout(context, attrs) { private var drawAlpha: Int = 255 - init { - setLayerType(View.LAYER_TYPE_SOFTWARE, null) - } - protected override fun onSetAlpha(alpha: Int): Boolean { - drawAlpha = alpha + // Ignore alpha passed from View, prefer to compute it from set values + drawAlpha = (255 * this.alpha * transitionAlpha).toInt() return true } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java index 2377057f1fc5..d9b7bde66c67 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -69,7 +69,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { (long) (125 * KeyguardPatternView.DISAPPEAR_MULTIPLIER_LOCKED), 0.6f /* translationScale */, 0.45f /* delayScale */, AnimationUtils.loadInterpolator( - mContext, android.R.interpolator.fast_out_linear_in)); + mContext, android.R.interpolator.fast_out_linear_in)); mDisappearYTranslation = getResources().getDimensionPixelSize( R.dimen.disappear_y_translation); mYTrans = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry); @@ -82,8 +82,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { } void onDevicePostureChanged(@DevicePostureInt int posture) { - mLastDevicePosture = posture; - updateMargins(); + if (mLastDevicePosture != posture) { + mLastDevicePosture = posture; + updateMargins(); + } } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index 38c07dc98471..2bdf46e1309d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -104,8 +104,10 @@ public class KeyguardPatternView extends KeyguardInputView } void onDevicePostureChanged(@DevicePostureInt int posture) { - mLastDevicePosture = posture; - updateMargins(); + if (mLastDevicePosture != posture) { + mLastDevicePosture = posture; + updateMargins(); + } } private void updateMargins() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 8f03eede1b1e..84f1da01c5c1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -164,13 +164,13 @@ import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent; -import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus; -import com.android.systemui.keyguard.shared.model.AuthenticationStatus; -import com.android.systemui.keyguard.shared.model.DetectionStatus; -import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus; -import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus; -import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus; -import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.AcquiredFaceAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus; +import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus; import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.WeatherData; @@ -1471,27 +1471,31 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private FaceAuthenticationListener mFaceAuthenticationListener = new FaceAuthenticationListener() { @Override - public void onAuthenticationStatusChanged(@NonNull AuthenticationStatus status) { - if (status instanceof AcquiredAuthenticationStatus) { + public void onAuthenticationStatusChanged( + @NonNull FaceAuthenticationStatus status + ) { + if (status instanceof AcquiredFaceAuthenticationStatus) { handleFaceAcquired( - ((AcquiredAuthenticationStatus) status).getAcquiredInfo()); - } else if (status instanceof ErrorAuthenticationStatus) { - ErrorAuthenticationStatus error = (ErrorAuthenticationStatus) status; + ((AcquiredFaceAuthenticationStatus) status).getAcquiredInfo()); + } else if (status instanceof ErrorFaceAuthenticationStatus) { + ErrorFaceAuthenticationStatus error = + (ErrorFaceAuthenticationStatus) status; handleFaceError(error.getMsgId(), error.getMsg()); - } else if (status instanceof FailedAuthenticationStatus) { + } else if (status instanceof FailedFaceAuthenticationStatus) { handleFaceAuthFailed(); - } else if (status instanceof HelpAuthenticationStatus) { - HelpAuthenticationStatus helpMsg = (HelpAuthenticationStatus) status; + } else if (status instanceof HelpFaceAuthenticationStatus) { + HelpFaceAuthenticationStatus helpMsg = + (HelpFaceAuthenticationStatus) status; handleFaceHelp(helpMsg.getMsgId(), helpMsg.getMsg()); - } else if (status instanceof SuccessAuthenticationStatus) { + } else if (status instanceof SuccessFaceAuthenticationStatus) { FaceManager.AuthenticationResult result = - ((SuccessAuthenticationStatus) status).getSuccessResult(); + ((SuccessFaceAuthenticationStatus) status).getSuccessResult(); handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric()); } } @Override - public void onDetectionStatusChanged(@NonNull DetectionStatus status) { + public void onDetectionStatusChanged(@NonNull FaceDetectionStatus status) { handleFaceAuthenticated(status.getUserId(), status.isStrongBiometric()); } }; diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt index 70b43713599b..a9779663cc7c 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt @@ -64,14 +64,6 @@ interface AuthenticationRepository { val isUnlocked: StateFlow<Boolean> /** - * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically - * dismisses once the authentication challenge is completed. For example, completing a biometric - * authentication challenge via face unlock or fingerprint sensor can automatically bypass the - * lock screen. - */ - val isBypassEnabled: StateFlow<Boolean> - - /** * Whether the auto confirm feature is enabled for the currently-selected user. * * Note that the length of the PIN is also important to take into consideration, please see @@ -113,9 +105,6 @@ interface AuthenticationRepository { */ suspend fun isLockscreenEnabled(): Boolean - /** See [isBypassEnabled]. */ - fun setBypassEnabled(isBypassEnabled: Boolean) - /** Reports an authentication attempt. */ suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) @@ -157,7 +146,7 @@ constructor( private val lockPatternUtils: LockPatternUtils, ) : AuthenticationRepository { - override val isUnlocked: StateFlow<Boolean> = keyguardRepository.isKeyguardUnlocked + override val isUnlocked = keyguardRepository.isKeyguardUnlocked override suspend fun isLockscreenEnabled(): Boolean { return withContext(backgroundDispatcher) { @@ -166,9 +155,6 @@ constructor( } } - private val _isBypassEnabled = MutableStateFlow(false) - override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow() - override val isAutoConfirmEnabled: StateFlow<Boolean> = userRepository.selectedUserInfo .map { it.id } @@ -225,10 +211,6 @@ constructor( } } - override fun setBypassEnabled(isBypassEnabled: Boolean) { - _isBypassEnabled.value = isBypassEnabled - } - override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) { val selectedUserId = userRepository.selectedUserId withContext(backgroundDispatcher) { diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt index 3283e406ddb0..b482977bde67 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.authentication.shared.model.AuthenticationThrottling import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.time.SystemClock import javax.inject.Inject @@ -51,6 +52,7 @@ constructor( private val repository: AuthenticationRepository, @Background private val backgroundDispatcher: CoroutineDispatcher, private val userRepository: UserRepository, + private val keyguardRepository: KeyguardRepository, private val clock: SystemClock, ) { /** @@ -76,14 +78,6 @@ constructor( initialValue = true, ) - /** - * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically - * dismisses once the authentication challenge is completed. For example, completing a biometric - * authentication challenge via face unlock or fingerprint sensor can automatically bypass the - * lock screen. - */ - val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled - /** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */ val throttling: StateFlow<AuthenticationThrottlingModel> = repository.throttling @@ -156,6 +150,16 @@ constructor( } /** + * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically + * dismisses once the authentication challenge is completed. For example, completing a biometric + * authentication challenge via face unlock or fingerprint sensor can automatically bypass the + * lock screen. + */ + fun isBypassEnabled(): Boolean { + return keyguardRepository.isBypassEnabled() + } + + /** * Attempts to authenticate the user and unlock the device. * * If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method @@ -218,11 +222,6 @@ constructor( return authenticationResult.isSuccessful } - /** See [isBypassEnabled]. */ - fun toggleBypassEnabled() { - repository.setBypassEnabled(!repository.isBypassEnabled.value) - } - /** Starts refreshing the throttling state every second. */ private suspend fun startThrottlingCountdown() { cancelCountdown() diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 7a2f2443dbd2..9df56fcce430 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -250,7 +250,7 @@ public class AuthContainerView extends LinearLayout .setMessage(messageBody) .setPositiveButton(android.R.string.ok, null) .create(); - alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL); + alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); alertDialog.show(); } @@ -263,7 +263,7 @@ public class AuthContainerView extends LinearLayout .setOnDismissListener( dialog -> animateAway(AuthDialogCallback.DISMISSED_ERROR)) .create(); - alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL); + alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); alertDialog.show(); } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt index 2abdb849cd9a..e3e9b3a3754a 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt @@ -16,10 +16,10 @@ package com.android.systemui.bouncer.domain.interactor +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.time.SystemClock @@ -35,8 +35,8 @@ constructor( private val keyguardStateController: KeyguardStateController, private val bouncerRepository: KeyguardBouncerRepository, private val biometricSettingsRepository: BiometricSettingsRepository, - private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, private val systemClock: SystemClock, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, ) { var receivedDownTouch = false val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible @@ -78,7 +78,7 @@ constructor( biometricSettingsRepository.isFingerprintEnrolled.value && biometricSettingsRepository.isStrongBiometricAllowed.value && biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value && - !deviceEntryFingerprintAuthRepository.isLockedOut.value && + !keyguardUpdateMonitor.isFingerprintLockedOut && !keyguardStateController.isUnlocked && !statusBarStateController.isDozing } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt index 0e224060a36f..f3a07fc53027 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt @@ -16,15 +16,52 @@ package com.android.systemui.dreams -import com.android.systemui.log.LogBuffer -import com.android.systemui.log.core.LogLevel -import com.android.systemui.log.dagger.DreamLog -import javax.inject.Inject +import com.android.systemui.log.core.Logger +import com.android.systemui.log.core.MessageBuffer /** Logs dream-related stuff to a {@link LogBuffer}. */ -class DreamLogger @Inject constructor(@DreamLog private val buffer: LogBuffer) { - /** Logs a debug message to the buffer. */ - fun d(tag: String, message: String) { - buffer.log(tag, LogLevel.DEBUG, { str1 = message }, { message }) - } +class DreamLogger(buffer: MessageBuffer, tag: String) : Logger(buffer, tag) { + fun logDreamOverlayEnabled(enabled: Boolean) = + d({ "Dream overlay enabled: $bool1" }) { bool1 = enabled } + + fun logIgnoreAddComplication(reason: String, complication: String) = + d({ "Ignore adding complication, reason: $str1, complication: $str2" }) { + str1 = reason + str2 = complication + } + + fun logIgnoreRemoveComplication(reason: String, complication: String) = + d({ "Ignore removing complication, reason: $str1, complication: $str2" }) { + str1 = reason + str2 = complication + } + + fun logAddComplication(complication: String) = + d({ "Add dream complication: $str1" }) { str1 = complication } + + fun logRemoveComplication(complication: String) = + d({ "Remove dream complication: $str1" }) { str1 = complication } + + fun logOverlayActive(active: Boolean) = d({ "Dream overlay active: $bool1" }) { bool1 = active } + + fun logLowLightActive(active: Boolean) = + d({ "Low light mode active: $bool1" }) { bool1 = active } + + fun logHasAssistantAttention(hasAttention: Boolean) = + d({ "Dream overlay has Assistant attention: $bool1" }) { bool1 = hasAttention } + + fun logStatusBarVisible(visible: Boolean) = + d({ "Dream overlay status bar visible: $bool1" }) { bool1 = visible } + + fun logAvailableComplicationTypes(types: Int) = + d({ "Available complication types: $int1" }) { int1 = types } + + fun logShouldShowComplications(showComplications: Boolean) = + d({ "Dream overlay should show complications: $bool1" }) { bool1 = showComplications } + + fun logShowOrHideStatusBarItem(show: Boolean, type: String) = + d({ "${if (bool1) "Showing" else "Hiding"} dream status bar item: $int1" }) { + bool1 = show + str1 = type + } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index 484bf3d51f36..01fb5227749f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -36,6 +36,9 @@ import com.android.systemui.complication.ComplicationLayoutParams.Position import com.android.systemui.dreams.dagger.DreamOverlayModule import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.log.dagger.DreamLog import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.policy.ConfigurationController @@ -65,12 +68,14 @@ constructor( private val mDreamInTranslationYDistance: Int, @Named(DreamOverlayModule.DREAM_IN_TRANSLATION_Y_DURATION) private val mDreamInTranslationYDurationMs: Long, - private val mLogger: DreamLogger, + @DreamLog logBuffer: LogBuffer, ) { companion object { private const val TAG = "DreamOverlayAnimationsController" } + private val logger = Logger(logBuffer, TAG) + private var mAnimator: Animator? = null private lateinit var view: View @@ -179,11 +184,11 @@ constructor( doOnEnd { mAnimator = null mOverlayStateController.setEntryAnimationsFinished(true) - mLogger.d(TAG, "Dream overlay entry animations finished.") + logger.d("Dream overlay entry animations finished.") } - doOnCancel { mLogger.d(TAG, "Dream overlay entry animations canceled.") } + doOnCancel { logger.d("Dream overlay entry animations canceled.") } start() - mLogger.d(TAG, "Dream overlay entry animations started.") + logger.d("Dream overlay entry animations started.") } } @@ -242,11 +247,11 @@ constructor( doOnEnd { mAnimator = null mOverlayStateController.setExitAnimationsRunning(false) - mLogger.d(TAG, "Dream overlay exit animations finished.") + logger.d("Dream overlay exit animations finished.") } - doOnCancel { mLogger.d(TAG, "Dream overlay exit animations canceled.") } + doOnCancel { logger.d("Dream overlay exit animations canceled.") } start() - mLogger.d(TAG, "Dream overlay exit animations started.") + logger.d("Dream overlay exit animations started.") } mOverlayStateController.setExitAnimationsRunning(true) return mAnimator as AnimatorSet diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java index c2421dcbc6ca..c9748f954670 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java @@ -28,6 +28,8 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.dagger.DreamLog; import com.android.systemui.statusbar.policy.CallbackController; import java.util.ArrayList; @@ -115,10 +117,10 @@ public class DreamOverlayStateController implements public DreamOverlayStateController(@Main Executor executor, @Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled, FeatureFlags featureFlags, - DreamLogger dreamLogger) { + @DreamLog LogBuffer logBuffer) { mExecutor = executor; mOverlayEnabled = overlayEnabled; - mLogger = dreamLogger; + mLogger = new DreamLogger(logBuffer, TAG); mFeatureFlags = featureFlags; if (mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)) { mSupportedTypes = Complication.COMPLICATION_TYPE_NONE @@ -126,7 +128,7 @@ public class DreamOverlayStateController implements } else { mSupportedTypes = Complication.COMPLICATION_TYPE_NONE; } - mLogger.d(TAG, "Dream overlay enabled: " + mOverlayEnabled); + mLogger.logDreamOverlayEnabled(mOverlayEnabled); } /** @@ -134,14 +136,13 @@ public class DreamOverlayStateController implements */ public void addComplication(Complication complication) { if (!mOverlayEnabled) { - mLogger.d(TAG, - "Ignoring adding complication due to overlay disabled: " + complication); + mLogger.logIgnoreAddComplication("overlay disabled", complication.toString()); return; } mExecutor.execute(() -> { if (mComplications.add(complication)) { - mLogger.d(TAG, "Added dream complication: " + complication); + mLogger.logAddComplication(complication.toString()); mCallbacks.stream().forEach(callback -> callback.onComplicationsChanged()); } }); @@ -152,14 +153,13 @@ public class DreamOverlayStateController implements */ public void removeComplication(Complication complication) { if (!mOverlayEnabled) { - mLogger.d(TAG, - "Ignoring removing complication due to overlay disabled: " + complication); + mLogger.logIgnoreRemoveComplication("overlay disabled", complication.toString()); return; } mExecutor.execute(() -> { if (mComplications.remove(complication)) { - mLogger.d(TAG, "Removed dream complication: " + complication); + mLogger.logRemoveComplication(complication.toString()); mCallbacks.stream().forEach(callback -> callback.onComplicationsChanged()); } }); @@ -305,7 +305,7 @@ public class DreamOverlayStateController implements * @param active {@code true} if overlay is active, {@code false} otherwise. */ public void setOverlayActive(boolean active) { - mLogger.d(TAG, "Dream overlay active: " + active); + mLogger.logOverlayActive(active); modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_DREAM_OVERLAY_ACTIVE); } @@ -314,7 +314,7 @@ public class DreamOverlayStateController implements * @param active {@code true} if low light mode is active, {@code false} otherwise. */ public void setLowLightActive(boolean active) { - mLogger.d(TAG, "Low light mode active: " + active); + mLogger.logLowLightActive(active); if (isLowLightActive() && !active) { // Notify that we're exiting low light only on the transition from active to not active. @@ -346,7 +346,7 @@ public class DreamOverlayStateController implements * @param hasAttention {@code true} if has the user's attention, {@code false} otherwise. */ public void setHasAssistantAttention(boolean hasAttention) { - mLogger.d(TAG, "Dream overlay has Assistant attention: " + hasAttention); + mLogger.logHasAssistantAttention(hasAttention); modifyState(hasAttention ? OP_SET_STATE : OP_CLEAR_STATE, STATE_HAS_ASSISTANT_ATTENTION); } @@ -355,7 +355,7 @@ public class DreamOverlayStateController implements * @param visible {@code true} if the status bar is visible, {@code false} otherwise. */ public void setDreamOverlayStatusBarVisible(boolean visible) { - mLogger.d(TAG, "Dream overlay status bar visible: " + visible); + mLogger.logStatusBarVisible(visible); modifyState( visible ? OP_SET_STATE : OP_CLEAR_STATE, STATE_DREAM_OVERLAY_STATUS_BAR_VISIBLE); } @@ -373,7 +373,7 @@ public class DreamOverlayStateController implements */ public void setAvailableComplicationTypes(@Complication.ComplicationType int types) { mExecutor.execute(() -> { - mLogger.d(TAG, "Available complication types: " + types); + mLogger.logAvailableComplicationTypes(types); mAvailableComplicationTypes = types; mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged); }); @@ -391,7 +391,7 @@ public class DreamOverlayStateController implements */ public void setShouldShowComplications(boolean shouldShowComplications) { mExecutor.execute(() -> { - mLogger.d(TAG, "Should show complications: " + shouldShowComplications); + mLogger.logShouldShowComplications(shouldShowComplications); mShouldShowComplications = shouldShowComplications; mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged); }); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java index 3a284083e844..a6401b6594ba 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java @@ -36,6 +36,8 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem; import com.android.systemui.dreams.dagger.DreamOverlayComponent; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.dagger.DreamLog; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; @@ -161,7 +163,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve DreamOverlayStatusBarItemsProvider statusBarItemsProvider, DreamOverlayStateController dreamOverlayStateController, UserTracker userTracker, - DreamLogger dreamLogger) { + @DreamLog LogBuffer logBuffer) { super(view); mResources = resources; mMainExecutor = mainExecutor; @@ -177,7 +179,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mZenModeController = zenModeController; mDreamOverlayStateController = dreamOverlayStateController; mUserTracker = userTracker; - mLogger = dreamLogger; + mLogger = new DreamLogger(logBuffer, TAG); // Register to receive show/hide updates for the system status bar. Our custom status bar // needs to hide when the system status bar is showing to ovoid overlapping status bars. @@ -346,8 +348,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve @Nullable String contentDescription) { mMainExecutor.execute(() -> { if (mIsAttached) { - mLogger.d(TAG, (show ? "Showing" : "Hiding") + " dream status bar item: " - + DreamOverlayStatusBarView.getLoggableStatusIconType(iconType)); + mLogger.logShowOrHideStatusBarItem( + show, DreamOverlayStatusBarView.getLoggableStatusIconType(iconType)); mView.showIcon(iconType, show, contentDescription); } }); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index b6f969d7b784..eb86c4392976 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -254,7 +254,7 @@ object Flags { /** Migrate the indication area to the new keyguard root view. */ // TODO(b/280067944): Tracking bug. @JvmField - val MIGRATE_INDICATION_AREA = unreleasedFlag(236, "migrate_indication_area", teamfood = true) + val MIGRATE_INDICATION_AREA = releasedFlag(236, "migrate_indication_area") /** * Migrate the bottom area to the new keyguard root view. @@ -294,6 +294,11 @@ object Flags { @JvmField val MIGRATE_NSSL = unreleasedFlag(242, "migrate_nssl") + /** Migrate the status view from the notification panel to keyguard root view. */ + // TODO(b/291767565): Tracking bug. + @JvmField + val MIGRATE_KEYGUARD_STATUS_VIEW = unreleasedFlag(243, "migrate_keyguard_status_view") + // 300 - power menu // TODO(b/254512600): Tracking Bug @JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite") @@ -429,10 +434,6 @@ object Flags { // TODO(b/266157412): Tracking Bug val MEDIA_RETAIN_SESSIONS = unreleasedFlag(913, "media_retain_sessions") - // TODO(b/266739309): Tracking Bug - @JvmField - val MEDIA_RECOMMENDATION_CARD_UPDATE = releasedFlag(914, "media_recommendation_card_update") - // TODO(b/267007629): Tracking Bug val MEDIA_RESUME_PROGRESS = releasedFlag(915, "media_resume_progress") diff --git a/packages/SystemUI/src/com/android/systemui/flags/ViewRefactorFlag.kt b/packages/SystemUI/src/com/android/systemui/flags/ViewRefactorFlag.kt new file mode 100644 index 000000000000..eaecda52a5a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/flags/ViewRefactorFlag.kt @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.flags + +import android.util.Log +import com.android.systemui.Dependency + +/** + * This class promotes best practices for flag guarding System UI view refactors. + * * [isEnabled] allows changing an implementation. + * * [assertDisabled] allows authors to flag code as being "dead" when the flag gets enabled and + * ensure that it is not being invoked accidentally in the post-flag refactor. + * * [expectEnabled] allows authors to guard new code with a "safe" alternative when invoked on + * flag-disabled builds, but with a check that should crash eng builds or tests when the + * expectation is violated. + * + * The constructors prefer that you provide a [FeatureFlags] instance, but does not require it, + * falling back to [Dependency.get]. This fallback should ONLY be used to flag-guard code changes + * inside views where injecting flag values after initialization can be error-prone. + */ +class ViewRefactorFlag +private constructor( + private val injectedFlags: FeatureFlags?, + private val flag: BooleanFlag, + private val readFlagValue: (FeatureFlags) -> Boolean +) { + @JvmOverloads + constructor( + flags: FeatureFlags? = null, + flag: UnreleasedFlag + ) : this(flags, flag, { it.isEnabled(flag) }) + + @JvmOverloads + constructor( + flags: FeatureFlags? = null, + flag: ReleasedFlag + ) : this(flags, flag, { it.isEnabled(flag) }) + + /** Whether the flag is enabled. Called to switch between an old behavior and a new behavior. */ + val isEnabled by lazy { + @Suppress("DEPRECATION") + val featureFlags = injectedFlags ?: Dependency.get(FeatureFlags::class.java) + readFlagValue(featureFlags) + } + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is enabled to ensure that the refactor author catches issues in testing. + * + * Example usage: + * ``` + * public void setController(NotificationShelfController notificationShelfController) { + * mShelfRefactor.assertDisabled(); + * mController = notificationShelfController; + * } + * ```` + */ + fun assertDisabled() = check(!isEnabled) { "Code path not supported when $flag is enabled." } + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an eng + * build to ensure that the refactor author catches issues in testing. + * + * Example usage: + * ``` + * public void setShelfIcons(NotificationIconContainer icons) { + * if (mShelfRefactor.expectEnabled()) { + * mShelfIcons = icons; + * } + * } + * ``` + */ + fun expectEnabled(): Boolean { + if (!isEnabled) { + val message = "Code path not supported when $flag is disabled." + Log.wtf(TAG, message, Exception(message)) + } + return isEnabled + } + + private companion object { + private const val TAG = "ViewRefactorFlag" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 468d7606933e..80a92340d3f3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -163,9 +163,11 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SystemSettings; import com.android.systemui.util.time.SystemClock; +import com.android.systemui.wallpapers.data.repository.WallpaperRepository; import com.android.wm.shell.keyguard.KeyguardTransitions; import dagger.Lazy; @@ -290,6 +292,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, public static final String SYS_BOOT_REASON_PROP = "sys.boot.reason.last"; public static final String REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"; private final DreamOverlayStateController mDreamOverlayStateController; + private final JavaAdapter mJavaAdapter; + private final WallpaperRepository mWallpaperRepository; /** The stream type that the lock sounds are tied to. */ private int mUiSoundsStreamType; @@ -1322,6 +1326,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, KeyguardTransitions keyguardTransitions, InteractionJankMonitor interactionJankMonitor, DreamOverlayStateController dreamOverlayStateController, + JavaAdapter javaAdapter, + WallpaperRepository wallpaperRepository, Lazy<ShadeController> shadeControllerLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, Lazy<ActivityLaunchAnimator> activityLaunchAnimator, @@ -1382,6 +1388,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mScreenOffAnimationController = screenOffAnimationController; mInteractionJankMonitor = interactionJankMonitor; mDreamOverlayStateController = dreamOverlayStateController; + mJavaAdapter = javaAdapter; + mWallpaperRepository = wallpaperRepository; mActivityLaunchAnimator = activityLaunchAnimator; mScrimControllerLazy = scrimControllerLazy; @@ -1484,6 +1492,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, com.android.internal.R.anim.lock_screen_behind_enter); mWorkLockController = new WorkLockActivityController(mContext, mUserTracker); + + mJavaAdapter.alwaysCollectFlow( + mWallpaperRepository.getWallpaperSupportsAmbientMode(), + this::setWallpaperSupportsAmbientMode); } // TODO(b/273443374) remove, temporary util to get a feature flag @@ -2964,6 +2976,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } private void onKeyguardExitFinished() { + if (DEBUG) Log.d(TAG, "onKeyguardExitFinished()"); // only play "unlock" noises if not on a call (since the incall UI // disables the keyguard) if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) { @@ -3185,13 +3198,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, flags |= StatusBarManager.DISABLE_RECENT; } - if (mPowerGestureIntercepted) { + if (mPowerGestureIntercepted && mOccluded && isSecure()) { flags |= StatusBarManager.DISABLE_RECENT; } if (DEBUG) { Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mOccluded=" + mOccluded + " isSecure=" + isSecure() + " force=" + forceHideHomeRecentsButtons + + " mPowerGestureIntercepted=" + mPowerGestureIntercepted + " --> flags=0x" + Integer.toHexString(flags)); } @@ -3419,6 +3433,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, pw.print(" mPendingLock: "); pw.println(mPendingLock); pw.print(" wakeAndUnlocking: "); pw.println(mWakeAndUnlocking); pw.print(" mPendingPinLock: "); pw.println(mPendingPinLock); + pw.print(" mPowerGestureIntercepted: "); pw.println(mPowerGestureIntercepted); } /** @@ -3458,7 +3473,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, * In case it does support it, we have to fade in the incoming app, otherwise we'll reveal it * with the light reveal scrim. */ - public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) { + private void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) { mWallpaperSupportsAmbientMode = supportsAmbientMode; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 29a2d12ca972..4205ed22ff24 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -66,9 +66,11 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SystemSettings; import com.android.systemui.util.time.SystemClock; +import com.android.systemui.wallpapers.data.repository.WallpaperRepository; import com.android.wm.shell.keyguard.KeyguardTransitions; import dagger.Lazy; @@ -130,6 +132,8 @@ public class KeyguardModule { KeyguardTransitions keyguardTransitions, InteractionJankMonitor interactionJankMonitor, DreamOverlayStateController dreamOverlayStateController, + JavaAdapter javaAdapter, + WallpaperRepository wallpaperRepository, Lazy<ShadeController> shadeController, Lazy<NotificationShadeWindowController> notificationShadeWindowController, Lazy<ActivityLaunchAnimator> activityLaunchAnimator, @@ -170,6 +174,8 @@ public class KeyguardModule { keyguardTransitions, interactionJankMonitor, dreamOverlayStateController, + javaAdapter, + wallpaperRepository, shadeController, notificationShadeWindowController, activityLaunchAnimator, 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 0b6c7c415599..ff3e77c46f1c 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 @@ -325,6 +325,9 @@ constructor( private class StrongAuthTracker(private val userRepository: UserRepository, context: Context?) : LockPatternUtils.StrongAuthTracker(context) { + private val selectedUserId = + userRepository.selectedUserInfo.map { it.id }.distinctUntilChanged() + // Backing field for onStrongAuthRequiredChanged private val _authFlags = MutableStateFlow(AuthenticationFlags(currentUserId, getStrongAuthForUser(currentUserId))) @@ -336,15 +339,12 @@ private class StrongAuthTracker(private val userRepository: UserRepository, cont ) val currentUserAuthFlags: Flow<AuthenticationFlags> = - userRepository.selectedUserInfo - .map { it.id } - .distinctUntilChanged() - .flatMapLatest { userId -> - _authFlags - .map { AuthenticationFlags(userId, getStrongAuthForUser(userId)) } - .onEach { Log.d(TAG, "currentUser authFlags changed, new value: $it") } - .onStart { emit(AuthenticationFlags(userId, getStrongAuthForUser(userId))) } - } + selectedUserId.flatMapLatest { userId -> + _authFlags + .map { AuthenticationFlags(userId, getStrongAuthForUser(userId)) } + .onEach { Log.d(TAG, "currentUser authFlags changed, new value: $it") } + .onStart { emit(AuthenticationFlags(userId, getStrongAuthForUser(userId))) } + } /** isStrongBiometricAllowed for the current user. */ val isStrongBiometricAllowed: Flow<Boolean> = @@ -352,16 +352,17 @@ private class StrongAuthTracker(private val userRepository: UserRepository, cont /** isNonStrongBiometricAllowed for the current user. */ val isNonStrongBiometricAllowed: Flow<Boolean> = - userRepository.selectedUserInfo - .map { it.id } - .distinctUntilChanged() + selectedUserId .flatMapLatest { userId -> _nonStrongBiometricAllowed .filter { it.first == userId } .map { it.second } - .onEach { Log.d(TAG, "isNonStrongBiometricAllowed changed for current user") } + .onEach { + Log.d(TAG, "isNonStrongBiometricAllowed changed for current user: $it") + } .onStart { emit(isNonStrongBiometricAllowedAfterIdleTimeout(userId)) } } + .and(isStrongBiometricAllowed) private val currentUserId get() = userRepository.getSelectedUserInfo().id @@ -387,3 +388,6 @@ private fun DevicePolicyManager.isFingerprintDisabled(userId: Int): Boolean = private fun DevicePolicyManager.isNotActive(userId: Int, policy: Int): Boolean = (getKeyguardDisabledFeatures(null, userId) and policy) == 0 + +private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>): Flow<Boolean> = + this.combine(anotherFlow) { a, b -> a && b } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index a3d1abedcc2c..6edf40f47521 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -38,13 +38,13 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.DetectionStatus -import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus -import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus -import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus -import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus +import com.android.systemui.keyguard.shared.model.AcquiredFaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus +import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.log.SessionTracker @@ -88,10 +88,10 @@ interface DeviceEntryFaceAuthRepository { val canRunFaceAuth: StateFlow<Boolean> /** Provide the current status of face authentication. */ - val authenticationStatus: Flow<AuthenticationStatus> + val authenticationStatus: Flow<FaceAuthenticationStatus> /** Provide the current status of face detection. */ - val detectionStatus: Flow<DetectionStatus> + val detectionStatus: Flow<FaceDetectionStatus> /** Current state of whether face authentication is locked out or not. */ val isLockedOut: StateFlow<Boolean> @@ -151,13 +151,13 @@ constructor( private var cancelNotReceivedHandlerJob: Job? = null private var halErrorRetryJob: Job? = null - private val _authenticationStatus: MutableStateFlow<AuthenticationStatus?> = + private val _authenticationStatus: MutableStateFlow<FaceAuthenticationStatus?> = MutableStateFlow(null) - override val authenticationStatus: Flow<AuthenticationStatus> + override val authenticationStatus: Flow<FaceAuthenticationStatus> get() = _authenticationStatus.filterNotNull() - private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null) - override val detectionStatus: Flow<DetectionStatus> + private val _detectionStatus = MutableStateFlow<FaceDetectionStatus?>(null) + override val detectionStatus: Flow<FaceDetectionStatus> get() = _detectionStatus.filterNotNull() private val _isLockedOut = MutableStateFlow(false) @@ -396,18 +396,18 @@ constructor( private val faceAuthCallback = object : FaceManager.AuthenticationCallback() { override fun onAuthenticationFailed() { - _authenticationStatus.value = FailedAuthenticationStatus + _authenticationStatus.value = FailedFaceAuthenticationStatus _isAuthenticated.value = false faceAuthLogger.authenticationFailed() onFaceAuthRequestCompleted() } override fun onAuthenticationAcquired(acquireInfo: Int) { - _authenticationStatus.value = AcquiredAuthenticationStatus(acquireInfo) + _authenticationStatus.value = AcquiredFaceAuthenticationStatus(acquireInfo) } override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) { - val errorStatus = ErrorAuthenticationStatus(errorCode, errString.toString()) + val errorStatus = ErrorFaceAuthenticationStatus(errorCode, errString.toString()) if (errorStatus.isLockoutError()) { _isLockedOut.value = true } @@ -433,11 +433,11 @@ constructor( if (faceAcquiredInfoIgnoreList.contains(code)) { return } - _authenticationStatus.value = HelpAuthenticationStatus(code, helpStr.toString()) + _authenticationStatus.value = HelpFaceAuthenticationStatus(code, helpStr.toString()) } override fun onAuthenticationSucceeded(result: FaceManager.AuthenticationResult) { - _authenticationStatus.value = SuccessAuthenticationStatus(result) + _authenticationStatus.value = SuccessFaceAuthenticationStatus(result) _isAuthenticated.value = true faceAuthLogger.faceAuthSuccess(result) onFaceAuthRequestCompleted() @@ -482,7 +482,7 @@ constructor( private val detectionCallback = FaceManager.FaceDetectionCallback { sensorId, userId, isStrong -> faceAuthLogger.faceDetected() - _detectionStatus.value = DetectionStatus(sensorId, userId, isStrong) + _detectionStatus.value = FaceDetectionStatus(sensorId, userId, isStrong) } private var cancellationInProgress = false 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 52234b32b83a..9bec30052476 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 @@ -21,27 +21,29 @@ import android.hardware.biometrics.BiometricAuthenticator.Modality import android.hardware.biometrics.BiometricSourceType import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback -import com.android.systemui.Dumpable import com.android.systemui.biometrics.AuthController import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dump.DumpManager -import java.io.PrintWriter +import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.stateIn /** Encapsulates state about device entry fingerprint auth mechanism. */ interface DeviceEntryFingerprintAuthRepository { /** Whether the device entry fingerprint auth is locked out. */ - val isLockedOut: StateFlow<Boolean> + val isLockedOut: Flow<Boolean> /** * Whether the fingerprint sensor is currently listening, this doesn't mean that the user is @@ -53,6 +55,9 @@ interface DeviceEntryFingerprintAuthRepository { * Fingerprint sensor type present on the device, null if fingerprint sensor is not available. */ val availableFpSensorType: Flow<BiometricType?> + + /** Provide the current status of fingerprint authentication. */ + val authenticationStatus: Flow<FingerprintAuthenticationStatus> } /** @@ -69,16 +74,7 @@ constructor( val authController: AuthController, val keyguardUpdateMonitor: KeyguardUpdateMonitor, @Application scope: CoroutineScope, - dumpManager: DumpManager, -) : DeviceEntryFingerprintAuthRepository, Dumpable { - - init { - dumpManager.registerDumpable(this) - } - - override fun dump(pw: PrintWriter, args: Array<String?>) { - pw.println("isLockedOut=${isLockedOut.value}") - } +) : DeviceEntryFingerprintAuthRepository { override val availableFpSensorType: Flow<BiometricType?> get() { @@ -114,7 +110,7 @@ constructor( else if (authController.isRearFpsSupported) BiometricType.REAR_FINGERPRINT else null } - override val isLockedOut: StateFlow<Boolean> = + override val isLockedOut: Flow<Boolean> = conflatedCallbackFlow { val sendLockoutUpdate = fun() { @@ -138,7 +134,7 @@ constructor( sendLockoutUpdate() awaitClose { keyguardUpdateMonitor.removeCallback(callback) } } - .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false) + .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) override val isRunning: Flow<Boolean> get() = conflatedCallbackFlow { @@ -166,6 +162,93 @@ constructor( awaitClose { keyguardUpdateMonitor.removeCallback(callback) } } + override val authenticationStatus: Flow<FingerprintAuthenticationStatus> + get() = conflatedCallbackFlow { + val callback = + object : KeyguardUpdateMonitorCallback() { + override fun onBiometricAuthenticated( + userId: Int, + biometricSourceType: BiometricSourceType, + isStrongBiometric: Boolean, + ) { + + sendUpdateIfFingerprint( + biometricSourceType, + SuccessFingerprintAuthenticationStatus( + userId, + isStrongBiometric, + ), + ) + } + + override fun onBiometricError( + msgId: Int, + errString: String?, + biometricSourceType: BiometricSourceType, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + ErrorFingerprintAuthenticationStatus( + msgId, + errString, + ), + ) + } + + override fun onBiometricHelp( + msgId: Int, + helpString: String?, + biometricSourceType: BiometricSourceType, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + HelpFingerprintAuthenticationStatus( + msgId, + helpString, + ), + ) + } + + override fun onBiometricAuthFailed( + biometricSourceType: BiometricSourceType, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + FailFingerprintAuthenticationStatus, + ) + } + + override fun onBiometricAcquired( + biometricSourceType: BiometricSourceType, + acquireInfo: Int, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + AcquiredFingerprintAuthenticationStatus( + acquireInfo, + ), + ) + } + + private fun sendUpdateIfFingerprint( + biometricSourceType: BiometricSourceType, + authenticationStatus: FingerprintAuthenticationStatus + ) { + if (biometricSourceType != BiometricSourceType.FINGERPRINT) { + return + } + + trySendWithFailureLogging( + authenticationStatus, + TAG, + "new fingerprint authentication status" + ) + } + } + keyguardUpdateMonitor.registerCallback(callback) + awaitClose { keyguardUpdateMonitor.removeCallback(callback) } + } + companion object { const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl" } 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 d119920e1a42..7475c4251211 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 @@ -31,26 +31,31 @@ import com.android.systemui.doze.DozeMachine import com.android.systemui.doze.DozeTransitionCallback import com.android.systemui.doze.DozeTransitionListener import com.android.systemui.dreams.DreamOverlayCallbackController +import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.shared.model.ScreenModel import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn @@ -147,6 +152,9 @@ interface KeyguardRepository { /** Observable for device wake/sleep state */ val wakefulness: StateFlow<WakefulnessModel> + /** Observable for device screen state */ + val screenModel: StateFlow<ScreenModel> + /** Observable for biometric unlock modes */ val biometricUnlockState: Flow<BiometricUnlockModel> @@ -162,6 +170,9 @@ interface KeyguardRepository { /** Whether quick settings or quick-quick settings is visible. */ val isQuickSettingsVisible: Flow<Boolean> + /** Receive an event for doze time tick */ + val dozeTimeTick: Flow<Unit> + /** * Returns `true` if the keyguard is showing; `false` otherwise. * @@ -171,6 +182,14 @@ interface KeyguardRepository { */ fun isKeyguardShowing(): Boolean + /** + * Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically + * dismissed once the authentication challenge is completed. For example, completing a biometric + * authentication challenge via face unlock or fingerprint sensor can automatically bypass the + * lock screen. + */ + fun isBypassEnabled(): Boolean + /** Sets whether the bottom area UI should animate the transition out of doze state. */ fun setAnimateDozingTransitions(animate: Boolean) @@ -195,6 +214,8 @@ interface KeyguardRepository { fun setIsDozing(isDozing: Boolean) fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean) + + fun dozeTimeTick() } /** Encapsulates application state for the keyguard. */ @@ -204,8 +225,10 @@ class KeyguardRepositoryImpl constructor( statusBarStateController: StatusBarStateController, wakefulnessLifecycle: WakefulnessLifecycle, + screenLifecycle: ScreenLifecycle, biometricUnlockController: BiometricUnlockController, private val keyguardStateController: KeyguardStateController, + private val keyguardBypassController: KeyguardBypassController, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val dozeTransitionListener: DozeTransitionListener, private val dozeParameters: DozeParameters, @@ -252,23 +275,17 @@ constructor( override val isAodAvailable: Flow<Boolean> = conflatedCallbackFlow { val callback = - object : DozeParameters.Callback { - override fun onAlwaysOnChange() { - trySendWithFailureLogging( - dozeParameters.getAlwaysOn(), - TAG, - "updated isAodAvailable" - ) - } + DozeParameters.Callback { + trySendWithFailureLogging( + dozeParameters.alwaysOn, + TAG, + "updated isAodAvailable" + ) } dozeParameters.addCallback(callback) // Adding the callback does not send an initial update. - trySendWithFailureLogging( - dozeParameters.getAlwaysOn(), - TAG, - "initial isAodAvailable" - ) + trySendWithFailureLogging(dozeParameters.alwaysOn, TAG, "initial isAodAvailable") awaitClose { dozeParameters.removeCallback(callback) } } @@ -366,6 +383,13 @@ constructor( _isDozing.value = isDozing } + private val _dozeTimeTick = MutableSharedFlow<Unit>() + override val dozeTimeTick = _dozeTimeTick.asSharedFlow() + + override fun dozeTimeTick() { + _dozeTimeTick.tryEmit(Unit) + } + private val _lastDozeTapToWakePosition = MutableStateFlow<Point?>(null) override val lastDozeTapToWakePosition = _lastDozeTapToWakePosition.asStateFlow() @@ -464,6 +488,10 @@ constructor( return keyguardStateController.isShowing } + override fun isBypassEnabled(): Boolean { + return keyguardBypassController.bypassEnabled + } + override val statusBarState: Flow<StatusBarState> = conflatedCallbackFlow { val callback = object : StatusBarStateController.StateListener { @@ -551,6 +579,42 @@ constructor( initialValue = WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle), ) + override val screenModel: StateFlow<ScreenModel> = + conflatedCallbackFlow { + val observer = + object : ScreenLifecycle.Observer { + override fun onScreenTurningOn() { + dispatchNewState() + } + override fun onScreenTurnedOn() { + dispatchNewState() + } + override fun onScreenTurningOff() { + dispatchNewState() + } + override fun onScreenTurnedOff() { + dispatchNewState() + } + + private fun dispatchNewState() { + trySendWithFailureLogging( + ScreenModel.fromScreenLifecycle(screenLifecycle), + TAG, + "updated screen state", + ) + } + } + + screenLifecycle.addObserver(observer) + awaitClose { screenLifecycle.removeObserver(observer) } + } + .stateIn( + scope, + // Use Eagerly so that we're always listening and never miss an event. + SharingStarted.Eagerly, + initialValue = ScreenModel.fromScreenLifecycle(screenLifecycle), + ) + override val fingerprintSensorLocation: Flow<Point?> = conflatedCallbackFlow { fun sendFpLocation() { trySendWithFailureLogging( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt index abe59b76816f..27e3a749a6c0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt @@ -18,8 +18,8 @@ package com.android.systemui.keyguard.data.repository import com.android.keyguard.FaceAuthUiEvent import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.DetectionStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -40,10 +40,10 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA private val _canRunFaceAuth = MutableStateFlow(false) override val canRunFaceAuth: StateFlow<Boolean> = _canRunFaceAuth - override val authenticationStatus: Flow<AuthenticationStatus> + override val authenticationStatus: Flow<FaceAuthenticationStatus> get() = emptyFlow() - override val detectionStatus: Flow<DetectionStatus> + override val detectionStatus: Flow<FaceDetectionStatus> get() = emptyFlow() private val _isLockedOut = MutableStateFlow(false) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BiometricMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BiometricMessageInteractor.kt new file mode 100644 index 000000000000..c849b8495a26 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BiometricMessageInteractor.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.domain.interactor + +import android.content.res.Resources +import android.hardware.biometrics.BiometricSourceType +import android.hardware.biometrics.BiometricSourceType.FINGERPRINT +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus +import com.android.systemui.keyguard.util.IndicationHelper +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterNot +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map + +/** + * BiometricMessage business logic. Filters biometric error/acquired/fail/success events for + * authentication events that should never surface a message to the user at the current device + * state. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class BiometricMessageInteractor +@Inject +constructor( + @Main private val resources: Resources, + private val fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, + private val fingerprintPropertyRepository: FingerprintPropertyRepository, + private val indicationHelper: IndicationHelper, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, +) { + val fingerprintErrorMessage: Flow<BiometricMessage> = + fingerprintAuthRepository.authenticationStatus + .filter { + it is ErrorFingerprintAuthenticationStatus && + !indicationHelper.shouldSuppressErrorMsg(FINGERPRINT, it.msgId) + } + .map { + val errorStatus = it as ErrorFingerprintAuthenticationStatus + BiometricMessage( + FINGERPRINT, + BiometricMessageType.ERROR, + errorStatus.msgId, + errorStatus.msg, + ) + } + + val fingerprintHelpMessage: Flow<BiometricMessage> = + fingerprintAuthRepository.authenticationStatus + .filter { it is HelpFingerprintAuthenticationStatus } + .filterNot { isPrimaryAuthRequired() } + .map { + val helpStatus = it as HelpFingerprintAuthenticationStatus + BiometricMessage( + FINGERPRINT, + BiometricMessageType.HELP, + helpStatus.msgId, + helpStatus.msg, + ) + } + + val fingerprintFailMessage: Flow<BiometricMessage> = + isUdfps().flatMapLatest { isUdfps -> + fingerprintAuthRepository.authenticationStatus + .filter { it is FailFingerprintAuthenticationStatus } + .filterNot { isPrimaryAuthRequired() } + .map { + BiometricMessage( + FINGERPRINT, + BiometricMessageType.FAIL, + BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED, + if (isUdfps) { + resources.getString( + com.android.internal.R.string.fingerprint_udfps_error_not_match + ) + } else { + resources.getString( + com.android.internal.R.string.fingerprint_error_not_match + ) + }, + ) + } + } + + private fun isUdfps() = + fingerprintPropertyRepository.sensorType.map { + it == FingerprintSensorType.UDFPS_OPTICAL || + it == FingerprintSensorType.UDFPS_ULTRASONIC + } + + private fun isPrimaryAuthRequired(): Boolean { + // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong + // as long as primary auth, i.e. PIN/pattern/password, is required), so it's ok to + // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the + // check of whether non-strong biometric is allowed since strong biometrics can still be + // used. + return !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */) + } +} + +data class BiometricMessage( + val source: BiometricSourceType, + val type: BiometricMessageType, + val id: Int, + val message: String?, +) + +enum class BiometricMessageType { + HELP, + ERROR, + FAIL, +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt index 2efcd0c1ffe7..0c898befe6a0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt @@ -35,4 +35,8 @@ constructor( fun setLastTapToWakePosition(position: Point) { keyguardRepository.setLastDozeTapToWakePosition(position) } + + fun dozeTimeTick() { + keyguardRepository.dozeTimeTick() + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt index 74ef7a50fd44..141b13055889 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt @@ -16,8 +16,8 @@ package com.android.systemui.keyguard.domain.interactor -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.DetectionStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus import kotlinx.coroutines.flow.Flow /** @@ -27,10 +27,10 @@ import kotlinx.coroutines.flow.Flow interface KeyguardFaceAuthInteractor { /** Current authentication status */ - val authenticationStatus: Flow<AuthenticationStatus> + val authenticationStatus: Flow<FaceAuthenticationStatus> /** Current detection status */ - val detectionStatus: Flow<DetectionStatus> + val detectionStatus: Flow<FaceDetectionStatus> /** Can face auth be run right now */ fun canFaceAuthRun(): Boolean @@ -72,8 +72,8 @@ interface KeyguardFaceAuthInteractor { */ interface FaceAuthenticationListener { /** Receive face authentication status updates */ - fun onAuthenticationStatusChanged(status: AuthenticationStatus) + fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus) /** Receive status updates whenever face detection runs */ - fun onDetectionStatusChanged(status: DetectionStatus) + fun onDetectionStatusChanged(status: FaceDetectionStatus) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 7fae7522d981..1553525915d5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -70,6 +70,8 @@ constructor( val dozeAmount: Flow<Float> = repository.linearDozeAmount /** Whether the system is in doze mode. */ val isDozing: Flow<Boolean> = repository.isDozing + /** Receive an event for doze time tick */ + val dozeTimeTick: Flow<Unit> = repository.dozeTimeTick /** Whether Always-on Display mode is available. */ val isAodAvailable: Flow<Boolean> = repository.isAodAvailable /** Doze transition information. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt index 5005b6c7f0df..10dd900e437e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt @@ -17,8 +17,8 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.DetectionStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow @@ -31,9 +31,9 @@ import kotlinx.coroutines.flow.emptyFlow */ @SysUISingleton class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInteractor { - override val authenticationStatus: Flow<AuthenticationStatus> + override val authenticationStatus: Flow<FaceAuthenticationStatus> get() = emptyFlow() - override val detectionStatus: Flow<DetectionStatus> + override val detectionStatus: Flow<FaceDetectionStatus> get() = emptyFlow() override fun canFaceAuthRun(): Boolean = false diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt index d467225a9d63..6e7a20b092f4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -30,8 +30,8 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.util.kotlin.pairwise @@ -165,10 +165,10 @@ constructor( repository.cancel() } - private val _authenticationStatusOverride = MutableStateFlow<AuthenticationStatus?>(null) + private val faceAuthenticationStatusOverride = MutableStateFlow<FaceAuthenticationStatus?>(null) /** Provide the status of face authentication */ override val authenticationStatus = - merge(_authenticationStatusOverride.filterNotNull(), repository.authenticationStatus) + merge(faceAuthenticationStatusOverride.filterNotNull(), repository.authenticationStatus) /** Provide the status of face detection */ override val detectionStatus = repository.detectionStatus @@ -176,13 +176,13 @@ constructor( private fun runFaceAuth(uiEvent: FaceAuthUiEvent, fallbackToDetect: Boolean) { if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) { if (repository.isLockedOut.value) { - _authenticationStatusOverride.value = - ErrorAuthenticationStatus( + faceAuthenticationStatusOverride.value = + ErrorFaceAuthenticationStatus( BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT, context.resources.getString(R.string.keyguard_face_unlock_unavailable) ) } else { - _authenticationStatusOverride.value = null + faceAuthenticationStatusOverride.value = null applicationScope.launch { faceAuthenticationLogger.authRequested(uiEvent) repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt index b354cfd27687..0f6d82ed4b5c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt @@ -23,33 +23,35 @@ import android.os.SystemClock.elapsedRealtime * Authentication status provided by * [com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository] */ -sealed class AuthenticationStatus +sealed class FaceAuthenticationStatus /** Success authentication status. */ -data class SuccessAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) : - AuthenticationStatus() +data class SuccessFaceAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) : + FaceAuthenticationStatus() /** Face authentication help message. */ -data class HelpAuthenticationStatus(val msgId: Int, val msg: String?) : AuthenticationStatus() +data class HelpFaceAuthenticationStatus(val msgId: Int, val msg: String?) : + FaceAuthenticationStatus() /** Face acquired message. */ -data class AcquiredAuthenticationStatus(val acquiredInfo: Int) : AuthenticationStatus() +data class AcquiredFaceAuthenticationStatus(val acquiredInfo: Int) : FaceAuthenticationStatus() /** Face authentication failed message. */ -object FailedAuthenticationStatus : AuthenticationStatus() +object FailedFaceAuthenticationStatus : FaceAuthenticationStatus() /** Face authentication error message */ -data class ErrorAuthenticationStatus( +data class ErrorFaceAuthenticationStatus( val msgId: Int, val msg: String? = null, // present to break equality check if the same error occurs repeatedly. val createdAt: Long = elapsedRealtime() -) : AuthenticationStatus() { +) : FaceAuthenticationStatus() { /** * Method that checks if [msgId] is a lockout error. A lockout error means that face * authentication is locked out. */ - fun isLockoutError() = msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT + fun isLockoutError() = + msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT || msgId == FaceManager.FACE_ERROR_LOCKOUT /** * Method that checks if [msgId] is a cancellation error. This means that face authentication @@ -64,4 +66,4 @@ data class ErrorAuthenticationStatus( } /** Face detection success message. */ -data class DetectionStatus(val sensorId: Int, val userId: Int, val isStrongBiometric: Boolean) +data class FaceDetectionStatus(val sensorId: Int, val userId: Int, val isStrongBiometric: Boolean) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt new file mode 100644 index 000000000000..7fc6016bf087 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.shared.model + +import android.os.SystemClock.elapsedRealtime + +/** + * Fingerprint authentication status provided by + * [com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository] + */ +sealed class FingerprintAuthenticationStatus + +/** Fingerprint authentication success status. */ +data class SuccessFingerprintAuthenticationStatus( + val userId: Int, + val isStrongBiometric: Boolean, +) : FingerprintAuthenticationStatus() + +/** Fingerprint authentication help message. */ +data class HelpFingerprintAuthenticationStatus( + val msgId: Int, + val msg: String?, +) : FingerprintAuthenticationStatus() + +/** Fingerprint acquired message. */ +data class AcquiredFingerprintAuthenticationStatus(val acquiredInfo: Int) : + FingerprintAuthenticationStatus() + +/** Fingerprint authentication failed message. */ +object FailFingerprintAuthenticationStatus : FingerprintAuthenticationStatus() + +/** Fingerprint authentication error message */ +data class ErrorFingerprintAuthenticationStatus( + val msgId: Int, + val msg: String? = null, + // present to break equality check if the same error occurs repeatedly. + val createdAt: Long = elapsedRealtime(), +) : FingerprintAuthenticationStatus() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenModel.kt new file mode 100644 index 000000000000..80a1b75c4350 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenModel.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.keyguard.shared.model + +import com.android.systemui.keyguard.ScreenLifecycle + +/** Model device screen lifecycle states. */ +data class ScreenModel( + val state: ScreenState, +) { + companion object { + fun fromScreenLifecycle(screenLifecycle: ScreenLifecycle): ScreenModel { + return ScreenModel(ScreenState.fromScreenLifecycleInt(screenLifecycle.getScreenState())) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenState.kt new file mode 100644 index 000000000000..fe5d9355a6fa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenState.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.shared.model + +import com.android.systemui.keyguard.ScreenLifecycle + +enum class ScreenState { + /** Screen is fully off. */ + SCREEN_OFF, + /** Signal that the screen is turning on. */ + SCREEN_TURNING_ON, + /** Screen is fully on. */ + SCREEN_ON, + /** Signal that the screen is turning off. */ + SCREEN_TURNING_OFF; + + companion object { + fun fromScreenLifecycleInt(value: Int): ScreenState { + return when (value) { + ScreenLifecycle.SCREEN_OFF -> SCREEN_OFF + ScreenLifecycle.SCREEN_TURNING_ON -> SCREEN_TURNING_ON + ScreenLifecycle.SCREEN_ON -> SCREEN_ON + ScreenLifecycle.SCREEN_TURNING_OFF -> SCREEN_TURNING_OFF + else -> throw IllegalArgumentException("Invalid screen value: $value") + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt index 728dd3911663..9872d97021fa 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsAodFingerprintViewBinder.kt @@ -37,6 +37,7 @@ object UdfpsAodFingerprintViewBinder { view: LottieAnimationView, viewModel: UdfpsAodViewModel, ) { + view.alpha = 0f view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsBackgroundViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsBackgroundViewBinder.kt index 26ef4685d286..0113628c30ca 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsBackgroundViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsBackgroundViewBinder.kt @@ -38,6 +38,7 @@ object UdfpsBackgroundViewBinder { view: ImageView, viewModel: BackgroundViewModel, ) { + view.alpha = 0f view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt index 0ab8e52fb6c7..bab04f234b3f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/UdfpsFingerprintViewBinder.kt @@ -42,6 +42,7 @@ object UdfpsFingerprintViewBinder { view: LottieAnimationView, viewModel: FingerprintViewModel, ) { + view.alpha = 0f view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt index 68cdfb6d5865..373f70582612 100644 --- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt @@ -4,7 +4,7 @@ import android.hardware.face.FaceManager import android.hardware.face.FaceSensorPropertiesInternal import com.android.keyguard.FaceAuthUiEvent import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.log.core.LogLevel.DEBUG import com.android.systemui.log.dagger.FaceAuthLog @@ -240,7 +240,7 @@ constructor( ) } - fun hardwareError(errorStatus: ErrorAuthenticationStatus) { + fun hardwareError(errorStatus: ErrorFaceAuthenticationStatus) { logBuffer.log( TAG, DEBUG, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt index 0b33904829d5..258284e8af51 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt @@ -31,15 +31,12 @@ import com.android.systemui.util.animation.TransitionLayout private const val TAG = "RecommendationViewHolder" /** ViewHolder for a Smartspace media recommendation. */ -class RecommendationViewHolder private constructor(itemView: View, updatedView: Boolean) { +class RecommendationViewHolder private constructor(itemView: View) { val recommendations = itemView as TransitionLayout // Recommendation screen - lateinit var cardIcon: ImageView - lateinit var mediaAppIcons: List<CachingIconView> - lateinit var mediaProgressBars: List<SeekBar> - lateinit var cardTitle: TextView + val cardTitle: TextView = itemView.requireViewById(R.id.media_rec_title) val mediaCoverContainers = listOf<ViewGroup>( @@ -47,53 +44,25 @@ class RecommendationViewHolder private constructor(itemView: View, updatedView: itemView.requireViewById(R.id.media_cover2_container), itemView.requireViewById(R.id.media_cover3_container) ) + val mediaAppIcons: List<CachingIconView> = + mediaCoverContainers.map { it.requireViewById(R.id.media_rec_app_icon) } val mediaTitles: List<TextView> = - if (updatedView) { - mediaCoverContainers.map { it.requireViewById(R.id.media_title) } - } else { - listOf( - itemView.requireViewById(R.id.media_title1), - itemView.requireViewById(R.id.media_title2), - itemView.requireViewById(R.id.media_title3) - ) - } + mediaCoverContainers.map { it.requireViewById(R.id.media_title) } val mediaSubtitles: List<TextView> = - if (updatedView) { - mediaCoverContainers.map { it.requireViewById(R.id.media_subtitle) } - } else { - listOf( - itemView.requireViewById(R.id.media_subtitle1), - itemView.requireViewById(R.id.media_subtitle2), - itemView.requireViewById(R.id.media_subtitle3) - ) + mediaCoverContainers.map { it.requireViewById(R.id.media_subtitle) } + val mediaProgressBars: List<SeekBar> = + mediaCoverContainers.map { + it.requireViewById<SeekBar?>(R.id.media_progress_bar).apply { + // Media playback is in the direction of tape, not time, so it stays LTR + layoutDirection = View.LAYOUT_DIRECTION_LTR + } } val mediaCoverItems: List<ImageView> = - if (updatedView) { - mediaCoverContainers.map { it.requireViewById(R.id.media_cover) } - } else { - listOf( - itemView.requireViewById(R.id.media_cover1), - itemView.requireViewById(R.id.media_cover2), - itemView.requireViewById(R.id.media_cover3) - ) - } + mediaCoverContainers.map { it.requireViewById(R.id.media_cover) } val gutsViewHolder = GutsViewHolder(itemView) init { - if (updatedView) { - mediaAppIcons = mediaCoverContainers.map { it.requireViewById(R.id.media_rec_app_icon) } - cardTitle = itemView.requireViewById(R.id.media_rec_title) - mediaProgressBars = - mediaCoverContainers.map { - it.requireViewById<SeekBar?>(R.id.media_progress_bar).apply { - // Media playback is in the direction of tape, not time, so it stays LTR - layoutDirection = View.LAYOUT_DIRECTION_LTR - } - } - } else { - cardIcon = itemView.requireViewById<ImageView>(R.id.recommendation_card_icon) - } (recommendations.background as IlluminationDrawable).let { background -> mediaCoverContainers.forEach { background.registerLightSource(it) } background.registerLightSource(gutsViewHolder.cancel) @@ -114,63 +83,31 @@ class RecommendationViewHolder private constructor(itemView: View, updatedView: * @param parent Parent of inflated view. */ @JvmStatic - fun create( - inflater: LayoutInflater, - parent: ViewGroup, - updatedView: Boolean, - ): RecommendationViewHolder { + fun create(inflater: LayoutInflater, parent: ViewGroup): RecommendationViewHolder { val itemView = - if (updatedView) { - inflater.inflate( - R.layout.media_recommendations, - parent, - false /* attachToRoot */ - ) - } else { - inflater.inflate( - R.layout.media_smartspace_recommendations, - parent, - false /* attachToRoot */ - ) - } + inflater.inflate(R.layout.media_recommendations, parent, false /* attachToRoot */) // Because this media view (a TransitionLayout) is used to measure and layout the views // in various states before being attached to its parent, we can't depend on the default // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction. itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE - return RecommendationViewHolder(itemView, updatedView) + return RecommendationViewHolder(itemView) } // Res Ids for the control components on the recommendation view. val controlsIds = setOf( - R.id.recommendation_card_icon, R.id.media_rec_title, - R.id.media_cover1, - R.id.media_cover2, - R.id.media_cover3, R.id.media_cover, R.id.media_cover1_container, R.id.media_cover2_container, R.id.media_cover3_container, - R.id.media_title1, - R.id.media_title2, - R.id.media_title3, R.id.media_title, - R.id.media_subtitle1, - R.id.media_subtitle2, - R.id.media_subtitle3, R.id.media_subtitle, ) val mediaTitlesAndSubtitlesIds = setOf( - R.id.media_title1, - R.id.media_title2, - R.id.media_title3, R.id.media_title, - R.id.media_subtitle1, - R.id.media_subtitle2, - R.id.media_subtitle3, R.id.media_subtitle, ) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt index 70b5e75e6048..398dcf260dff 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt @@ -744,11 +744,7 @@ constructor( val newRecs = mediaControlPanelFactory.get() newRecs.attachRecommendation( - RecommendationViewHolder.create( - LayoutInflater.from(context), - mediaContent, - mediaFlags.isRecommendationCardUpdateEnabled() - ) + RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent) ) newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index a978b92cb234..a12bc2c99d63 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -784,14 +784,7 @@ public class MediaControlPanel { contentDescription = mRecommendationViewHolder.getGutsViewHolder().getGutsText().getText(); } else if (data != null) { - if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { - contentDescription = mContext.getString( - R.string.controls_media_smartspace_rec_header); - } else { - contentDescription = mContext.getString( - R.string.controls_media_smartspace_rec_description, - data.getAppName(mContext)); - } + contentDescription = mContext.getString(R.string.controls_media_smartspace_rec_header); } else { contentDescription = null; } @@ -1377,10 +1370,6 @@ public class MediaControlPanel { PackageManager packageManager = mContext.getPackageManager(); // Set up media source app's logo. Drawable icon = packageManager.getApplicationIcon(applicationInfo); - if (!mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { - ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon(); - headerLogoImageView.setImageDrawable(icon); - } fetchAndUpdateRecommendationColors(icon); // Set up media rec card's tap action if applicable. @@ -1401,16 +1390,7 @@ public class MediaControlPanel { // Set up media item cover. ImageView mediaCoverImageView = mediaCoverItems.get(itemIndex); - if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { - bindRecommendationArtwork( - recommendation, - data.getPackageName(), - itemIndex - ); - } else { - mediaCoverImageView.post( - () -> mediaCoverImageView.setImageIcon(recommendation.getIcon())); - } + bindRecommendationArtwork(recommendation, data.getPackageName(), itemIndex); // Set up the media item's click listener if applicable. ViewGroup mediaCoverContainer = mediaCoverContainers.get(itemIndex); @@ -1455,21 +1435,18 @@ public class MediaControlPanel { subtitleView.setText(subtitle); // Set up progress bar - if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { - SeekBar mediaProgressBar = - mRecommendationViewHolder.getMediaProgressBars().get(itemIndex); - TextView mediaSubtitle = - mRecommendationViewHolder.getMediaSubtitles().get(itemIndex); - // show progress bar if the recommended album is played. - Double progress = MediaDataUtils.getDescriptionProgress(recommendation.getExtras()); - if (progress == null || progress <= 0.0) { - mediaProgressBar.setVisibility(View.GONE); - mediaSubtitle.setVisibility(View.VISIBLE); - } else { - mediaProgressBar.setProgress((int) (progress * 100)); - mediaProgressBar.setVisibility(View.VISIBLE); - mediaSubtitle.setVisibility(View.GONE); - } + SeekBar mediaProgressBar = + mRecommendationViewHolder.getMediaProgressBars().get(itemIndex); + TextView mediaSubtitle = mRecommendationViewHolder.getMediaSubtitles().get(itemIndex); + // show progress bar if the recommended album is played. + Double progress = MediaDataUtils.getDescriptionProgress(recommendation.getExtras()); + if (progress == null || progress <= 0.0) { + mediaProgressBar.setVisibility(View.GONE); + mediaSubtitle.setVisibility(View.VISIBLE); + } else { + mediaProgressBar.setProgress((int) (progress * 100)); + mediaProgressBar.setVisibility(View.VISIBLE); + mediaSubtitle.setVisibility(View.GONE); } } mSmartspaceMediaItemsCount = NUM_REQUIRED_RECOMMENDATIONS; @@ -1588,9 +1565,7 @@ public class MediaControlPanel { int textPrimaryColor = MediaColorSchemesKt.textPrimaryFromScheme(colorScheme); int textSecondaryColor = MediaColorSchemesKt.textSecondaryFromScheme(colorScheme); - if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { - mRecommendationViewHolder.getCardTitle().setTextColor(textPrimaryColor); - } + mRecommendationViewHolder.getCardTitle().setTextColor(textPrimaryColor); mRecommendationViewHolder.getRecommendations() .setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); @@ -1598,12 +1573,9 @@ public class MediaControlPanel { (title) -> title.setTextColor(textPrimaryColor)); mRecommendationViewHolder.getMediaSubtitles().forEach( (subtitle) -> subtitle.setTextColor(textSecondaryColor)); - if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { - mRecommendationViewHolder.getMediaProgressBars().forEach( - (progressBar) -> progressBar.setProgressTintList( - ColorStateList.valueOf(textPrimaryColor)) - ); - } + mRecommendationViewHolder.getMediaProgressBars().forEach( + (progressBar) -> progressBar.setProgressTintList( + ColorStateList.valueOf(textPrimaryColor))); mRecommendationViewHolder.getGutsViewHolder().setColors(colorScheme); } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt index 4bca778b77c5..1dd969f9bea5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt @@ -655,13 +655,8 @@ constructor( expandedLayout.load(context, R.xml.media_session_expanded) } TYPE.RECOMMENDATION -> { - if (mediaFlags.isRecommendationCardUpdateEnabled()) { - collapsedLayout.load(context, R.xml.media_recommendations_view_collapsed) - expandedLayout.load(context, R.xml.media_recommendations_view_expanded) - } else { - collapsedLayout.load(context, R.xml.media_recommendation_collapsed) - expandedLayout.load(context, R.xml.media_recommendation_expanded) - } + collapsedLayout.load(context, R.xml.media_recommendations_collapsed) + expandedLayout.load(context, R.xml.media_recommendations_expanded) } } refreshState() diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt index 42a6b7cf4b0d..f2db088ced83 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt @@ -40,10 +40,6 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) { */ fun isRetainingPlayersEnabled() = featureFlags.isEnabled(Flags.MEDIA_RETAIN_SESSIONS) - /** Check whether we show the updated recommendation card. */ - fun isRecommendationCardUpdateEnabled() = - featureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE) - /** Check whether to get progress information for resume players */ fun isResumeProgressEnabled() = featureFlags.isEnabled(Flags.MEDIA_RESUME_PROGRESS) diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt index eb1ca66f6ca8..809edc09070a 100644 --- a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt @@ -70,6 +70,19 @@ constructor( } } + /** + * Wakes up the device if dreaming with a screensaver. + * + * @param why a string explaining why we're waking the device for debugging purposes. Should be + * in SCREAMING_SNAKE_CASE. + * @param wakeReason the PowerManager-based reason why we're waking the device. + */ + fun wakeUpIfDreaming(why: String, @PowerManager.WakeReason wakeReason: Int) { + if (statusBarStateController.isDreaming) { + repository.wakeUp(why, wakeReason) + } + } + companion object { private const val FSI_WAKE_WHY = "full_screen_intent" } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index 83b373d5e626..856a92e85ad7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -58,6 +58,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { private final BrightnessSliderController mBrightnessSliderController; private final BrightnessMirrorHandler mBrightnessMirrorHandler; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private boolean mListening; private View.OnTouchListener mTileLayoutTouchListener = new View.OnTouchListener() { @Override @@ -159,12 +160,15 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { public void setListening(boolean listening, boolean expanded) { setListening(listening && expanded); - // Set the listening as soon as the QS fragment starts listening regardless of the - //expansion, so it will update the current brightness before the slider is visible. - if (listening) { - mBrightnessController.registerCallbacks(); - } else { - mBrightnessController.unregisterCallbacks(); + if (listening != mListening) { + mListening = listening; + // Set the listening as soon as the QS fragment starts listening regardless of the + //expansion, so it will update the current brightness before the slider is visible. + if (listening) { + mBrightnessController.registerCallbacks(); + } else { + mBrightnessController.unregisterCallbacks(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt index 285ff74f8b2e..b23c4ec9aa8b 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt @@ -77,7 +77,7 @@ constructor( authenticationInteractor.isUnlocked .map { isUnlocked -> val currentSceneKey = sceneInteractor.currentScene(CONTAINER_NAME).value.key - val isBypassEnabled = authenticationInteractor.isBypassEnabled.value + val isBypassEnabled = authenticationInteractor.isBypassEnabled() when { isUnlocked -> when (currentSceneKey) { diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt index 5aa5feeedcf1..f9324a95c1e5 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt @@ -16,19 +16,25 @@ package com.android.systemui.scene.ui.view +import android.view.Gravity +import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout import androidx.activity.OnBackPressedDispatcher import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner +import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.R import com.android.systemui.compose.ComposeFacade import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.scene.shared.model.Scene import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel +import java.time.Instant import kotlinx.coroutines.launch object SceneWindowRootViewBinder { @@ -77,6 +83,9 @@ object SceneWindowRootViewBinder { ) ) + val legacyView = view.requireViewById<View>(R.id.legacy_window_root) + view.addView(createVisibilityToggleView(legacyView)) + launch { viewModel.isVisible.collect { isVisible -> onVisibilityChangedInternal(isVisible) @@ -89,4 +98,28 @@ object SceneWindowRootViewBinder { } } } + + private var clickCount = 0 + private var lastClick = Instant.now() + + /** + * A temporary UI to toggle on/off the visibility of the given [otherView]. It is toggled by + * tapping 5 times in quick succession on the device camera (top center). + */ + // TODO(b/291321285): Remove this when the Flexiglass UI is mature enough to turn off legacy + // SysUI altogether. + private fun createVisibilityToggleView(otherView: View): View { + val toggleView = View(otherView.context) + toggleView.layoutParams = FrameLayout.LayoutParams(200, 200, Gravity.CENTER_HORIZONTAL) + toggleView.setOnClickListener { + val now = Instant.now() + clickCount = if (now.minusSeconds(2) > lastClick) 1 else clickCount + 1 + if (clickCount == 5) { + otherView.isVisible = !otherView.isVisible + clickCount = 0 + } + lastClick = now + } + return toggleView + } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java index 9594ba374fc3..6af9b739da52 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java @@ -22,7 +22,6 @@ import static com.android.settingslib.display.BrightnessUtils.convertLinearToGam import android.animation.ValueAnimator; import android.annotation.NonNull; -import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.display.BrightnessInfo; @@ -31,10 +30,10 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; import android.os.HandlerExecutor; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -43,6 +42,8 @@ import android.service.vr.IVrStateCallbacks; import android.util.Log; import android.util.MathUtils; +import androidx.annotation.Nullable; + import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -52,10 +53,13 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.BrightnessMirrorController; +import com.android.systemui.util.settings.SecureSettings; import java.util.concurrent.Executor; -import javax.inject.Inject; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController { private static final String TAG = "CentralSurfaces.BrightnessController"; @@ -75,8 +79,11 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig private final DisplayManager mDisplayManager; private final UserTracker mUserTracker; private final DisplayTracker mDisplayTracker; + @Nullable private final IVrManager mVrManager; + private final SecureSettings mSecureSettings; + private final Executor mMainExecutor; private final Handler mBackgroundHandler; private final BrightnessObserver mBrightnessObserver; @@ -106,6 +113,8 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig /** ContentObserver to watch brightness */ private class BrightnessObserver extends ContentObserver { + private boolean mObserving = false; + BrightnessObserver(Handler handler) { super(handler); } @@ -124,19 +133,17 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig } public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.unregisterContentObserver(this); - cr.registerContentObserver( - BRIGHTNESS_MODE_URI, - false, this, UserHandle.USER_ALL); - mDisplayTracker.addBrightnessChangeCallback(mBrightnessListener, - new HandlerExecutor(mHandler)); + if (!mObserving) { + mObserving = true; + mSecureSettings.registerContentObserverForUser( + BRIGHTNESS_MODE_URI, + false, this, UserHandle.USER_ALL); + } } public void stopObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.unregisterContentObserver(this); - mDisplayTracker.removeCallback(mBrightnessListener); + mSecureSettings.unregisterContentObserver(this); + mObserving = false; } } @@ -159,6 +166,8 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig } mBrightnessObserver.startObserving(); + mDisplayTracker.addBrightnessChangeCallback(mBrightnessListener, + new HandlerExecutor(mMainHandler)); mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); // Update the slider and mode before attaching the listener so we don't @@ -166,7 +175,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig mUpdateModeRunnable.run(); mUpdateSliderRunnable.run(); - mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER); + mMainHandler.sendEmptyMessage(MSG_ATTACH_LISTENER); } }; @@ -187,9 +196,10 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig } mBrightnessObserver.stopObserving(); + mDisplayTracker.removeCallback(mBrightnessListener); mUserTracker.removeCallback(mUserChangedCallback); - mHandler.sendEmptyMessage(MSG_DETACH_LISTENER); + mMainHandler.sendEmptyMessage(MSG_DETACH_LISTENER); } }; @@ -225,7 +235,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig mBrightnessMin = info.brightnessMinimum; // Value is passed as intbits, since this is what the message takes. final int valueAsIntBits = Float.floatToIntBits(info.brightness); - mHandler.obtainMessage(MSG_UPDATE_SLIDER, valueAsIntBits, + mMainHandler.obtainMessage(MSG_UPDATE_SLIDER, valueAsIntBits, inVrMode ? 1 : 0).sendToTarget(); } }; @@ -233,14 +243,14 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { @Override public void onVrStateChanged(boolean enabled) { - mHandler.obtainMessage(MSG_VR_MODE_CHANGED, enabled ? 1 : 0, 0) + mMainHandler.obtainMessage(MSG_VR_MODE_CHANGED, enabled ? 1 : 0, 0) .sendToTarget(); } }; - private final Handler mHandler = new Handler() { + private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override - public void handleMessage(Message msg) { + public boolean handleMessage(Message msg) { mExternalChange = true; try { switch (msg.what) { @@ -257,14 +267,18 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig updateVrMode(msg.arg1 != 0); break; default: - super.handleMessage(msg); + return false; + } } finally { mExternalChange = false; } + return true; } }; + private final Handler mMainHandler; + private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() { @Override @@ -274,12 +288,17 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig } }; + @AssistedInject public BrightnessController( Context context, - ToggleSlider control, + @Assisted ToggleSlider control, UserTracker userTracker, DisplayTracker displayTracker, + DisplayManager displayManager, + SecureSettings secureSettings, + @Nullable IVrManager iVrManager, @Main Executor mainExecutor, + @Main Looper mainLooper, @Background Handler bgHandler) { mContext = context; mControl = control; @@ -288,22 +307,23 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig mBackgroundHandler = bgHandler; mUserTracker = userTracker; mDisplayTracker = displayTracker; - mBrightnessObserver = new BrightnessObserver(mHandler); - + mSecureSettings = secureSettings; mDisplayId = mContext.getDisplayId(); - PowerManager pm = context.getSystemService(PowerManager.class); + mDisplayManager = displayManager; + mVrManager = iVrManager; - mDisplayManager = context.getSystemService(DisplayManager.class); - mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService( - Context.VR_SERVICE)); + mMainHandler = new Handler(mainLooper, mHandlerCallback); + mBrightnessObserver = new BrightnessObserver(mMainHandler); } public void registerCallbacks() { + mBackgroundHandler.removeCallbacks(mStartListeningRunnable); mBackgroundHandler.post(mStartListeningRunnable); } /** Unregister all call backs, both to and from the controller */ public void unregisterCallbacks() { + mBackgroundHandler.removeCallbacks(mStopListeningRunnable); mBackgroundHandler.post(mStopListeningRunnable); mControlValueInitialized = false; } @@ -418,38 +438,12 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig mSliderAnimator.start(); } - /** Factory for creating a {@link BrightnessController}. */ - public static class Factory { - private final Context mContext; - private final UserTracker mUserTracker; - private final DisplayTracker mDisplayTracker; - private final Executor mMainExecutor; - private final Handler mBackgroundHandler; - - @Inject - public Factory( - Context context, - UserTracker userTracker, - DisplayTracker displayTracker, - @Main Executor mainExecutor, - @Background Handler bgHandler) { - mContext = context; - mUserTracker = userTracker; - mDisplayTracker = displayTracker; - mMainExecutor = mainExecutor; - mBackgroundHandler = bgHandler; - } + + /** Factory for creating a {@link BrightnessController}. */ + @AssistedFactory + public interface Factory { /** Create a {@link BrightnessController} */ - public BrightnessController create(ToggleSlider toggleSlider) { - return new BrightnessController( - mContext, - toggleSlider, - mUserTracker, - mDisplayTracker, - mMainExecutor, - mBackgroundHandler); - } + BrightnessController create(ToggleSlider toggleSlider); } - } diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java index 182e4569b549..38b1f14e45de 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java @@ -23,7 +23,6 @@ import static android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KE import android.app.Activity; import android.graphics.Rect; import android.os.Bundle; -import android.os.Handler; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; @@ -37,10 +36,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.settings.DisplayTracker; -import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -56,26 +52,21 @@ public class BrightnessDialog extends Activity { private BrightnessController mBrightnessController; private final BrightnessSliderController.Factory mToggleSliderFactory; - private final UserTracker mUserTracker; - private final DisplayTracker mDisplayTracker; + private final BrightnessController.Factory mBrightnessControllerFactory; private final DelayableExecutor mMainExecutor; - private final Handler mBackgroundHandler; private final AccessibilityManagerWrapper mAccessibilityMgr; private Runnable mCancelTimeoutRunnable; @Inject public BrightnessDialog( - UserTracker userTracker, - DisplayTracker displayTracker, - BrightnessSliderController.Factory factory, + BrightnessSliderController.Factory brightnessSliderfactory, + BrightnessController.Factory brightnessControllerFactory, @Main DelayableExecutor mainExecutor, - @Background Handler bgHandler, - AccessibilityManagerWrapper accessibilityMgr) { - mUserTracker = userTracker; - mDisplayTracker = displayTracker; - mToggleSliderFactory = factory; + AccessibilityManagerWrapper accessibilityMgr + ) { + mToggleSliderFactory = brightnessSliderfactory; + mBrightnessControllerFactory = brightnessControllerFactory; mMainExecutor = mainExecutor; - mBackgroundHandler = bgHandler; mAccessibilityMgr = accessibilityMgr; } @@ -121,8 +112,7 @@ public class BrightnessDialog extends Activity { controller.init(); frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT); - mBrightnessController = new BrightnessController( - this, controller, mUserTracker, mDisplayTracker, mMainExecutor, mBackgroundHandler); + mBrightnessController = mBrightnessControllerFactory.create(controller); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/shade/LockscreenHostedDreamGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/LockscreenHostedDreamGestureListener.kt new file mode 100644 index 000000000000..45fc68a793bd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/LockscreenHostedDreamGestureListener.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import android.os.PowerManager +import android.view.GestureDetector +import android.view.MotionEvent +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.FalsingManager.LOW_PENALTY +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.statusbar.StatusBarState +import javax.inject.Inject + +/** + * This gestureListener will wake up by tap when the device is dreaming but not dozing, and the + * selected screensaver is hosted in lockscreen. Tap is gated by the falsing manager. + * + * Touches go through the [NotificationShadeWindowViewController]. + */ +@SysUISingleton +class LockscreenHostedDreamGestureListener +@Inject +constructor( + private val falsingManager: FalsingManager, + private val powerInteractor: PowerInteractor, + private val statusBarStateController: StatusBarStateController, + private val primaryBouncerInteractor: PrimaryBouncerInteractor, + private val keyguardRepository: KeyguardRepository, + private val shadeLogger: ShadeLogger, +) : GestureDetector.SimpleOnGestureListener() { + private val TAG = this::class.simpleName + + override fun onSingleTapUp(e: MotionEvent): Boolean { + if (shouldHandleMotionEvent()) { + if (!falsingManager.isFalseTap(LOW_PENALTY)) { + shadeLogger.d("$TAG#onSingleTapUp tap handled, requesting wakeUpIfDreaming") + powerInteractor.wakeUpIfDreaming( + "DREAMING_SINGLE_TAP", + PowerManager.WAKE_REASON_TAP + ) + } else { + shadeLogger.d("$TAG#onSingleTapUp false tap ignored") + } + return true + } + return false + } + + private fun shouldHandleMotionEvent(): Boolean { + return keyguardRepository.isActiveDreamLockscreenHosted.value && + statusBarStateController.state == StatusBarState.KEYGUARD && + !primaryBouncerInteractor.isBouncerShowing() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index ea15035a6c6f..9399d48be5f3 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -168,7 +168,6 @@ import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; -import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; @@ -224,6 +223,8 @@ import com.android.systemui.util.Utils; import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.animation.FlingAnimationUtils; +import kotlin.Unit; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; @@ -234,8 +235,6 @@ import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Provider; -import kotlin.Unit; - import kotlinx.coroutines.CoroutineDispatcher; @SysUISingleton @@ -440,8 +439,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final FalsingCollector mFalsingCollector; private final ShadeHeadsUpTrackerImpl mShadeHeadsUpTracker = new ShadeHeadsUpTrackerImpl(); private final ShadeFoldAnimator mShadeFoldAnimator = new ShadeFoldAnimatorImpl(); - private final ShadeNotificationPresenterImpl mShadeNotificationPresenter = - new ShadeNotificationPresenterImpl(); private boolean mShowIconsWhenExpanded; private int mIndicationBottomPadding; @@ -1473,7 +1470,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // so we should not add a padding for them stackScrollerPadding = 0; } else { - stackScrollerPadding = mQsController.getUnlockedStackScrollerPadding(); + stackScrollerPadding = mQsController.getHeaderHeight(); } } else { stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded; @@ -1520,7 +1517,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump userSwitcherPreferredY, darkAmount, mOverStretchAmount, bypassEnabled, - mQsController.getUnlockedStackScrollerPadding(), + mQsController.getHeaderHeight(), mQsController.computeExpansionFraction(), mDisplayTopInset, mSplitShadeEnabled, @@ -3323,23 +3320,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump ).printTableData(ipw); } - private final class ShadeNotificationPresenterImpl implements ShadeNotificationPresenter{ - @Override - public RemoteInputController.Delegate createRemoteInputDelegate() { - return mNotificationStackScrollLayoutController.createDelegate(); - } - - @Override - public boolean hasPulsingNotifications() { - return mNotificationListContainer.hasPulsingNotifications(); - } - } - - @Override - public ShadeNotificationPresenter getShadeNotificationPresenter() { - return mShadeNotificationPresenter; - } - @Override public void initDependencies( CentralSurfaces centralSurfaces, diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 481da52635f0..1f401fbbe6c1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -543,7 +543,6 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW state.forceUserActivity, state.launchingActivityFromNotification, state.mediaBackdropShowing, - state.wallpaperSupportsAmbientMode, state.windowNotTouchable, state.componentsForcingTopUi, state.forceOpenTokens, @@ -734,12 +733,6 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW apply(mCurrentState); } - @Override - public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) { - mCurrentState.wallpaperSupportsAmbientMode = supportsAmbientMode; - apply(mCurrentState); - } - /** * @param state The {@link StatusBarStateController} of the status bar. */ diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt index 7812f07fc59c..d25294343d2f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt @@ -46,7 +46,6 @@ class NotificationShadeWindowState( @JvmField var forceUserActivity: Boolean = false, @JvmField var launchingActivityFromNotification: Boolean = false, @JvmField var mediaBackdropShowing: Boolean = false, - @JvmField var wallpaperSupportsAmbientMode: Boolean = false, @JvmField var windowNotTouchable: Boolean = false, @JvmField var componentsForcingTopUi: MutableSet<String> = mutableSetOf(), @JvmField var forceOpenTokens: MutableSet<Any> = mutableSetOf(), @@ -84,7 +83,6 @@ class NotificationShadeWindowState( forceUserActivity.toString(), launchingActivityFromNotification.toString(), mediaBackdropShowing.toString(), - wallpaperSupportsAmbientMode.toString(), windowNotTouchable.toString(), componentsForcingTopUi.toString(), forceOpenTokens.toString(), @@ -124,7 +122,6 @@ class NotificationShadeWindowState( forceUserActivity: Boolean, launchingActivity: Boolean, backdropShowing: Boolean, - wallpaperSupportsAmbientMode: Boolean, notTouchable: Boolean, componentsForcingTopUi: MutableSet<String>, forceOpenTokens: MutableSet<Any>, @@ -153,7 +150,6 @@ class NotificationShadeWindowState( this.forceUserActivity = forceUserActivity this.launchingActivityFromNotification = launchingActivity this.mediaBackdropShowing = backdropShowing - this.wallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode this.windowNotTouchable = notTouchable this.componentsForcingTopUi.clear() this.componentsForcingTopUi.addAll(componentsForcingTopUi) @@ -200,7 +196,6 @@ class NotificationShadeWindowState( "forceUserActivity", "launchingActivity", "backdropShowing", - "wallpaperSupportsAmbientMode", "notTouchable", "componentsForcingTopUi", "forceOpenTokens", diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 5c41d572149c..108ea68ae8e0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -16,6 +16,7 @@ package com.android.systemui.shade; +import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; @@ -46,6 +47,7 @@ import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder; import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.compose.ComposeFacade; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dock.DockManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; @@ -72,7 +74,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import com.android.systemui.util.time.SystemClock; @@ -87,7 +88,7 @@ import javax.inject.Provider; /** * Controller for {@link NotificationShadeWindowView}. */ -@CentralSurfacesComponent.CentralSurfacesScope +@SysUISingleton public class NotificationShadeWindowViewController { private static final String TAG = "NotifShadeWindowVC"; private final FalsingCollector mFalsingCollector; @@ -102,9 +103,12 @@ public class NotificationShadeWindowViewController { private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final AmbientState mAmbientState; private final PulsingGestureListener mPulsingGestureListener; + private final LockscreenHostedDreamGestureListener mLockscreenHostedDreamGestureListener; private final NotificationInsetsController mNotificationInsetsController; private final boolean mIsTrackpadCommonEnabled; + private final FeatureFlags mFeatureFlags; private GestureDetector mPulsingWakeupGestureHandler; + private GestureDetector mDreamingWakeupGestureHandler; private View mBrightnessMirror; private boolean mTouchActive; private boolean mTouchCancelled; @@ -156,6 +160,7 @@ public class NotificationShadeWindowViewController { NotificationInsetsController notificationInsetsController, AmbientState ambientState, PulsingGestureListener pulsingGestureListener, + LockscreenHostedDreamGestureListener lockscreenHostedDreamGestureListener, KeyguardBouncerViewModel keyguardBouncerViewModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory, KeyguardMessageAreaController.Factory messageAreaControllerFactory, @@ -187,8 +192,10 @@ public class NotificationShadeWindowViewController { mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; mAmbientState = ambientState; mPulsingGestureListener = pulsingGestureListener; + mLockscreenHostedDreamGestureListener = lockscreenHostedDreamGestureListener; mNotificationInsetsController = notificationInsetsController; mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON); + mFeatureFlags = featureFlags; // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); @@ -237,7 +244,10 @@ public class NotificationShadeWindowViewController { mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller); mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(), mPulsingGestureListener); - + if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) { + mDreamingWakeupGestureHandler = new GestureDetector(mView.getContext(), + mLockscreenHostedDreamGestureListener); + } mView.setLayoutInsetsController(mNotificationInsetsController); mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() { @Override @@ -291,6 +301,10 @@ public class NotificationShadeWindowViewController { mFalsingCollector.onTouchEvent(ev); mPulsingWakeupGestureHandler.onTouchEvent(ev); + if (mDreamingWakeupGestureHandler != null + && mDreamingWakeupGestureHandler.onTouchEvent(ev)) { + return true; + } if (mStatusBarKeyguardViewManager.dispatchTouchEvent(ev)) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 025c461110ef..baac57ca44ba 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -233,7 +233,6 @@ public class QuickSettingsController implements Dumpable { private int mMaxExpansionHeight; /** Expansion fraction of the notification shade */ private float mShadeExpandedFraction; - private int mPeekHeight; private float mLastOverscroll; private boolean mExpansionFromOverscroll; private boolean mExpansionEnabledPolicy = true; @@ -429,7 +428,6 @@ public class QuickSettingsController implements Dumpable { final ViewConfiguration configuration = ViewConfiguration.get(this.mPanelView.getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); - mPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height); mStatusBarMinHeight = SystemBarUtils.getStatusBarHeight(mPanelView.getContext()); mScrimCornerRadius = mResources.getDimensionPixelSize( R.dimen.notification_scrim_corner_radius); @@ -500,12 +498,7 @@ public class QuickSettingsController implements Dumpable { } int getHeaderHeight() { - return mQs.getHeader().getHeight(); - } - - /** Returns the padding of the stackscroller when unlocked */ - int getUnlockedStackScrollerPadding() { - return (mQs != null ? mQs.getHeader().getHeight() : 0) + mPeekHeight; + return isQsFragmentCreated() ? mQs.getHeader().getHeight() : 0; } private boolean isRemoteInputActiveWithKeyboardUp() { @@ -2090,8 +2083,6 @@ public class QuickSettingsController implements Dumpable { ipw.println(mMaxExpansionHeight); ipw.print("mShadeExpandedFraction="); ipw.println(mShadeExpandedFraction); - ipw.print("mPeekHeight="); - ipw.println(mPeekHeight); ipw.print("mLastOverscroll="); ipw.println(mLastOverscroll); ipw.print("mExpansionFromOverscroll="); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt index 8d5c30b51677..2532bad1d7a7 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt @@ -18,6 +18,7 @@ package com.android.systemui.shade import android.view.ViewPropertyAnimator import com.android.systemui.statusbar.GestureRecorder import com.android.systemui.statusbar.NotificationShelfController +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.HeadsUpManagerPhone @@ -63,6 +64,9 @@ interface ShadeSurface : ShadeViewController { /** Animates the view from its current alpha to zero then runs the runnable. */ fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable): ViewPropertyAnimator + /** Returns the NSSL controller. */ + val notificationStackScrollLayoutController: NotificationStackScrollLayoutController + /** Set whether the bouncer is showing. */ fun setBouncerShowing(bouncerShowing: Boolean) diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt index 9aa5eb0cd68b..d5b5c87ec781 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt @@ -19,9 +19,7 @@ import android.view.MotionEvent import android.view.ViewGroup import android.view.ViewTreeObserver import com.android.systemui.keyguard.shared.model.WakefulnessModel -import com.android.systemui.statusbar.RemoteInputController import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.HeadsUpAppearanceController import com.android.systemui.statusbar.phone.KeyguardStatusBarView import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController @@ -141,9 +139,6 @@ interface ShadeViewController { /** Returns the StatusBarState. */ val barState: Int - /** Returns the NSSL controller. */ - val notificationStackScrollLayoutController: NotificationStackScrollLayoutController - /** Sets the amount of progress in the status bar launch animation. */ fun applyLaunchAnimationProgress(linearProgress: Float) @@ -261,9 +256,6 @@ interface ShadeViewController { /** Returns the ShadeFoldAnimator. */ val shadeFoldAnimator: ShadeFoldAnimator - /** Returns the ShadeNotificationPresenter. */ - val shadeNotificationPresenter: ShadeNotificationPresenter - companion object { /** * Returns a multiplicative factor to use when determining the falsing threshold for touches @@ -325,16 +317,7 @@ interface ShadeFoldAnimator { fun cancelFoldToAodAnimation() /** Returns the main view of the shade. */ - val view: ViewGroup -} - -/** Handles the shade's interactions with StatusBarNotificationPresenter. */ -interface ShadeNotificationPresenter { - /** Returns a new delegate for some view controller pieces of the remote input process. */ - fun createRemoteInputDelegate(): RemoteInputController.Delegate - - /** Returns whether the screen has temporarily woken up to display notifications. */ - fun hasPulsingNotifications(): Boolean + val view: ViewGroup? } /** diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt new file mode 100644 index 000000000000..287ac528385f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import android.view.MotionEvent +import android.view.ViewGroup +import android.view.ViewTreeObserver +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.phone.HeadsUpAppearanceController +import java.util.function.Consumer +import javax.inject.Inject + +/** Empty implementation of ShadeViewController for variants with no shade. */ +class ShadeViewControllerEmptyImpl @Inject constructor() : ShadeViewController { + override fun expand(animate: Boolean) {} + override fun expandToQs() {} + override fun expandToNotifications() {} + override val isExpandingOrCollapsing: Boolean = false + override val isExpanded: Boolean = false + override val isPanelExpanded: Boolean = false + override val isShadeFullyExpanded: Boolean = false + override fun collapse(delayed: Boolean, speedUpFactor: Float) {} + override fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float) {} + override fun collapseWithDuration(animationDuration: Int) {} + override fun instantCollapse() {} + override fun animateCollapseQs(fullyCollapse: Boolean) {} + override fun canBeCollapsed(): Boolean = false + override val isCollapsing: Boolean = false + override val isFullyCollapsed: Boolean = false + override val isTracking: Boolean = false + override val isViewEnabled: Boolean = false + override fun setOpenCloseListener(openCloseListener: OpenCloseListener) {} + override fun shouldHideStatusBarIconsWhenExpanded() = false + override fun blockExpansionForCurrentTouch() {} + override fun setTrackingStartedListener(trackingStartedListener: TrackingStartedListener) {} + override fun disableHeader(state1: Int, state2: Int, animated: Boolean) {} + override fun startExpandLatencyTracking() {} + override fun startBouncerPreHideAnimation() {} + override fun dozeTimeTick() {} + override fun resetViews(animate: Boolean) {} + override val barState: Int = 0 + override fun applyLaunchAnimationProgress(linearProgress: Float) {} + override fun closeUserSwitcherIfOpen(): Boolean { + return false + } + override fun onBackPressed() {} + override fun setIsLaunchAnimationRunning(running: Boolean) {} + override fun setAlpha(alpha: Int, animate: Boolean) {} + override fun setAlphaChangeAnimationEndAction(r: Runnable) {} + override fun setPulsing(pulsing: Boolean) {} + override fun setQsScrimEnabled(qsScrimEnabled: Boolean) {} + override fun setAmbientIndicationTop(ambientIndicationTop: Int, ambientTextVisible: Boolean) {} + override fun updateSystemUiStateFlags() {} + override fun updateTouchableRegion() {} + override fun addOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener) {} + override fun removeOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener) {} + override fun postToView(action: Runnable): Boolean { + return false + } + override fun transitionToExpandedShade(delay: Long) {} + override val isUnlockHintRunning: Boolean = false + + override fun resetViewGroupFade() {} + override fun setKeyguardTransitionProgress(keyguardAlpha: Float, keyguardTranslationY: Int) {} + override fun setOverStretchAmount(amount: Float) {} + override fun setKeyguardStatusBarAlpha(alpha: Float) {} + override fun showAodUi() {} + override fun isFullyExpanded(): Boolean { + return false + } + override fun handleExternalTouch(event: MotionEvent): Boolean { + return false + } + override fun startTrackingExpansionFromStatusBar() {} + override val shadeHeadsUpTracker = ShadeHeadsUpTrackerEmptyImpl() + override val shadeFoldAnimator = ShadeFoldAnimatorEmptyImpl() +} + +class ShadeHeadsUpTrackerEmptyImpl : ShadeHeadsUpTracker { + override fun addTrackingHeadsUpListener(listener: Consumer<ExpandableNotificationRow>) {} + override fun removeTrackingHeadsUpListener(listener: Consumer<ExpandableNotificationRow>) {} + override fun setHeadsUpAppearanceController( + headsUpAppearanceController: HeadsUpAppearanceController? + ) {} + override val trackedHeadsUpNotification: ExpandableNotificationRow? = null +} + +class ShadeFoldAnimatorEmptyImpl : ShadeFoldAnimator { + override fun prepareFoldToAodAnimation() {} + override fun startFoldToAodAnimation( + startAction: Runnable, + endAction: Runnable, + cancelAction: Runnable, + ) {} + override fun cancelFoldToAodAnimation() {} + override val view: ViewGroup? = null +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java index 4ec5f46e7771..7a989cfe227a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar; import android.view.View; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; import com.android.systemui.statusbar.notification.stack.AmbientState; @@ -52,7 +51,6 @@ public class LegacyNotificationShelfControllerImpl implements NotificationShelfC mActivatableNotificationViewController = activatableNotificationViewController; mKeyguardBypassController = keyguardBypassController; mStatusBarStateController = statusBarStateController; - mView.setSensitiveRevealAnimEnabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)); mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java index 47a4641bcdd9..5ac542b3530f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java @@ -112,9 +112,6 @@ public interface NotificationShadeWindowController extends RemoteInputController /** Sets the state of whether heads up is showing or not. */ default void setHeadsUpShowing(boolean showing) {} - /** Sets whether the wallpaper supports ambient mode or not. */ - default void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) {} - /** Gets whether the wallpaper is showing or not. */ default boolean isShowingWallpaper() { return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 25a1dc6322ba..3f37c60bee8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -24,7 +24,6 @@ import android.content.res.Resources; import android.graphics.Rect; import android.util.AttributeSet; import android.util.IndentingPrintWriter; -import android.util.Log; import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; @@ -40,6 +39,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; import com.android.systemui.animation.ShadeInterpolation; +import com.android.systemui.flags.Flags; +import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; import com.android.systemui.statusbar.notification.NotificationUtils; @@ -95,8 +96,10 @@ public class NotificationShelf extends ActivatableNotificationView implements St private float mCornerAnimationDistance; private NotificationShelfController mController; private float mActualWidth = -1; - private boolean mSensitiveRevealAnimEnabled; - private boolean mShelfRefactorFlagEnabled; + private final ViewRefactorFlag mSensitiveRevealAnim = + new ViewRefactorFlag(Flags.SENSITIVE_REVEAL_ANIM); + private final ViewRefactorFlag mShelfRefactor = + new ViewRefactorFlag(Flags.NOTIFICATION_SHELF_REFACTOR); private boolean mCanModifyColorOfNotifications; private boolean mCanInteract; private NotificationStackScrollLayout mHostLayout; @@ -130,7 +133,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St public void bind(AmbientState ambientState, NotificationStackScrollLayoutController hostLayoutController) { - assertRefactorFlagDisabled(); + mShelfRefactor.assertDisabled(); mAmbientState = ambientState; mHostLayoutController = hostLayoutController; hostLayoutController.setOnNotificationRemovedListener((child, isTransferInProgress) -> { @@ -140,7 +143,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout, NotificationRoundnessManager roundnessManager) { - if (!checkRefactorFlagEnabled()) return; + if (!mShelfRefactor.expectEnabled()) return; mAmbientState = ambientState; mHostLayout = hostLayout; mRoundnessManager = roundnessManager; @@ -268,7 +271,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight(); - if (mSensitiveRevealAnimEnabled && viewState.hidden) { + if (mSensitiveRevealAnim.isEnabled() && viewState.hidden) { // if the shelf is hidden, position it at the end of the stack (plus the clip // padding), such that when it appears animated, it will smoothly move in from the // bottom, without jump cutting any notifications @@ -279,7 +282,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private int getSpeedBumpIndex() { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mHostLayout.getSpeedBumpIndex(); } else { return mHostLayoutController.getSpeedBumpIndex(); @@ -413,7 +416,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St expandingAnimated, isLastChild, shelfClipStart); // TODO(b/172289889) scale mPaddingBetweenElements with expansion amount - if ((!mSensitiveRevealAnimEnabled && ((isLastChild && !child.isInShelf()) + if ((!mSensitiveRevealAnim.isEnabled() && ((isLastChild && !child.isInShelf()) || backgroundForceHidden)) || aboveShelf) { notificationClipEnd = shelfStart + getIntrinsicHeight(); } else { @@ -462,7 +465,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St // if the shelf is visible, but if the shelf is hidden, it causes incorrect curling. // notificationClipEnd handles the discrepancy between a visible and hidden shelf, // so we use that when on the keyguard (and while animating away) to reduce curling. - final float keyguardSafeShelfStart = !mSensitiveRevealAnimEnabled + final float keyguardSafeShelfStart = !mSensitiveRevealAnim.isEnabled() && mAmbientState.isOnKeyguard() ? notificationClipEnd : shelfStart; updateCornerRoundnessOnScroll(anv, viewStart, keyguardSafeShelfStart); } @@ -504,7 +507,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private ExpandableView getHostLayoutChildAt(int index) { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return (ExpandableView) mHostLayout.getChildAt(index); } else { return mHostLayoutController.getChildAt(index); @@ -512,7 +515,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private int getHostLayoutChildCount() { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mHostLayout.getChildCount(); } else { return mHostLayoutController.getChildCount(); @@ -520,7 +523,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private boolean canModifyColorOfNotifications() { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mCanModifyColorOfNotifications && mAmbientState.isShadeExpanded(); } else { return mController.canModifyColorOfNotifications(); @@ -583,7 +586,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private boolean isViewAffectedBySwipe(ExpandableView expandableView) { - if (!mShelfRefactorFlagEnabled) { + if (!mShelfRefactor.isEnabled()) { return mHostLayoutController.isViewAffectedBySwipe(expandableView); } else { return mRoundnessManager.isViewAffectedBySwipe(expandableView); @@ -607,7 +610,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private View getHostLayoutTransientView(int index) { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mHostLayout.getTransientView(index); } else { return mHostLayoutController.getTransientView(index); @@ -615,7 +618,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private int getHostLayoutTransientViewCount() { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mHostLayout.getTransientViewCount(); } else { return mHostLayoutController.getTransientViewCount(); @@ -961,7 +964,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St @Override public void onStateChanged(int newState) { - assertRefactorFlagDisabled(); + mShelfRefactor.assertDisabled(); mStatusBarState = newState; updateInteractiveness(); } @@ -975,7 +978,7 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private boolean canInteract() { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mCanInteract; } else { return mStatusBarState == StatusBarState.KEYGUARD; @@ -1018,32 +1021,18 @@ public class NotificationShelf extends ActivatableNotificationView implements St return false; } - private void assertRefactorFlagDisabled() { - if (mShelfRefactorFlagEnabled) { - NotificationShelfController.throwIllegalFlagStateError(false); - } - } - - private boolean checkRefactorFlagEnabled() { - if (!mShelfRefactorFlagEnabled) { - Log.wtf(TAG, - "Code path not supported when Flags.NOTIFICATION_SHELF_REFACTOR is disabled."); - } - return mShelfRefactorFlagEnabled; - } - public void setController(NotificationShelfController notificationShelfController) { - assertRefactorFlagDisabled(); + mShelfRefactor.assertDisabled(); mController = notificationShelfController; } public void setCanModifyColorOfNotifications(boolean canModifyColorOfNotifications) { - if (!checkRefactorFlagEnabled()) return; + if (!mShelfRefactor.expectEnabled()) return; mCanModifyColorOfNotifications = canModifyColorOfNotifications; } public void setCanInteract(boolean canInteract) { - if (!checkRefactorFlagEnabled()) return; + if (!mShelfRefactor.expectEnabled()) return; mCanInteract = canInteract; updateInteractiveness(); } @@ -1053,27 +1042,15 @@ public class NotificationShelf extends ActivatableNotificationView implements St } private int getIndexOfViewInHostLayout(ExpandableView child) { - if (mShelfRefactorFlagEnabled) { + if (mShelfRefactor.isEnabled()) { return mHostLayout.indexOfChild(child); } else { return mHostLayoutController.indexOfChild(child); } } - /** - * Set whether the sensitive reveal animation feature flag is enabled - * @param enabled true if enabled - */ - public void setSensitiveRevealAnimEnabled(boolean enabled) { - mSensitiveRevealAnimEnabled = enabled; - } - - public void setRefactorFlagEnabled(boolean enabled) { - mShelfRefactorFlagEnabled = enabled; - } - public void requestRoundnessResetFor(ExpandableView child) { - if (!checkRefactorFlagEnabled()) return; + if (!mShelfRefactor.expectEnabled()) return; child.requestRoundnessReset(SHELF_SCROLL); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt index 1619ddaac85c..8a3e21756c2a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt @@ -16,11 +16,8 @@ package com.android.systemui.statusbar -import android.util.Log import android.view.View import android.view.View.OnClickListener -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.statusbar.notification.stack.AmbientState import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout @@ -49,29 +46,4 @@ interface NotificationShelfController { /** @see View.setOnClickListener */ fun setOnClickListener(listener: OnClickListener) - - companion object { - @JvmStatic - fun assertRefactorFlagDisabled(featureFlags: FeatureFlags) { - if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { - throwIllegalFlagStateError(expected = false) - } - } - - @JvmStatic - fun checkRefactorFlagEnabled(featureFlags: FeatureFlags): Boolean = - featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR).also { enabled -> - if (!enabled) { - Log.wtf("NotifShelf", getErrorMessage(expected = true)) - } - } - - @JvmStatic - fun throwIllegalFlagStateError(expected: Boolean): Nothing = - error(getErrorMessage(expected)) - - private fun getErrorMessage(expected: Boolean): String = - "Code path not supported when Flags.NOTIFICATION_SHELF_REFACTOR is " + - if (expected) "disabled" else "enabled" - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt index 1cf9c1e1f299..1c5aa3cce266 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt @@ -3,10 +3,10 @@ package com.android.systemui.statusbar.notification import android.util.FloatProperty import android.view.View import androidx.annotation.FloatRange -import com.android.systemui.Dependency import com.android.systemui.R import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.flags.ViewRefactorFlag import com.android.systemui.statusbar.notification.stack.AnimationProperties import com.android.systemui.statusbar.notification.stack.StackStateAnimator import kotlin.math.abs @@ -46,14 +46,14 @@ interface Roundable { @JvmDefault val topCornerRadius: Float get() = - if (roundableState.newHeadsUpAnimFlagEnabled) roundableState.topCornerRadius + if (roundableState.newHeadsUpAnim.isEnabled) roundableState.topCornerRadius else topRoundness * maxRadius /** Current bottom corner in pixel, based on [bottomRoundness] and [maxRadius] */ @JvmDefault val bottomCornerRadius: Float get() = - if (roundableState.newHeadsUpAnimFlagEnabled) roundableState.bottomCornerRadius + if (roundableState.newHeadsUpAnim.isEnabled) roundableState.bottomCornerRadius else bottomRoundness * maxRadius /** Get and update the current radii */ @@ -335,13 +335,12 @@ constructor( internal val targetView: View, private val roundable: Roundable, maxRadius: Float, - private val featureFlags: FeatureFlags = Dependency.get(FeatureFlags::class.java) + featureFlags: FeatureFlags? = null ) { internal var maxRadius = maxRadius private set - internal val newHeadsUpAnimFlagEnabled - get() = featureFlags.isEnabled(Flags.IMPROVED_HUN_ANIMATIONS) + internal val newHeadsUpAnim = ViewRefactorFlag(featureFlags, Flags.IMPROVED_HUN_ANIMATIONS) /** Animatable for top roundness */ private val topAnimatable = topAnimatable(roundable) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinator.kt new file mode 100644 index 000000000000..d268e358690f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinator.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.coordinator + +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * Filter out notifications on the lockscreen if the lockscreen hosted dream is active. If the user + * stops dreaming, pulls the shade down or unlocks the device, then the notifications are unhidden. + */ +@CoordinatorScope +class DreamCoordinator +@Inject +constructor( + private val statusBarStateController: SysuiStatusBarStateController, + @Application private val scope: CoroutineScope, + private val keyguardRepository: KeyguardRepository, +) : Coordinator { + private var isOnKeyguard = false + private var isLockscreenHostedDream = false + + override fun attach(pipeline: NotifPipeline) { + pipeline.addPreGroupFilter(filter) + statusBarStateController.addCallback(statusBarStateListener) + scope.launch { attachFilterOnDreamingStateChange() } + recordStatusBarState(statusBarStateController.state) + } + + private val filter = + object : NotifFilter("LockscreenHostedDreamFilter") { + var isFiltering = false + override fun shouldFilterOut(entry: NotificationEntry, now: Long): Boolean { + return isFiltering + } + inline fun update(msg: () -> String) { + val wasFiltering = isFiltering + isFiltering = isLockscreenHostedDream && isOnKeyguard + if (wasFiltering != isFiltering) { + invalidateList(msg()) + } + } + } + + private val statusBarStateListener = + object : StatusBarStateController.StateListener { + override fun onStateChanged(newState: Int) { + recordStatusBarState(newState) + } + } + + private suspend fun attachFilterOnDreamingStateChange() { + keyguardRepository.isActiveDreamLockscreenHosted.collect { isDreaming -> + recordDreamingState(isDreaming) + } + } + + private fun recordStatusBarState(newState: Int) { + isOnKeyguard = newState == StatusBarState.KEYGUARD + filter.update { "recordStatusBarState: " + StatusBarState.toString(newState) } + } + + private fun recordDreamingState(isDreaming: Boolean) { + isLockscreenHostedDream = isDreaming + filter.update { "recordLockscreenHostedDreamState: $isDreaming" } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt index e5953cfc07cd..0ccab9e46b72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt @@ -15,6 +15,8 @@ */ package com.android.systemui.statusbar.notification.collection.coordinator +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.PipelineDumpable import com.android.systemui.statusbar.notification.collection.PipelineDumper @@ -31,32 +33,34 @@ interface NotifCoordinators : Coordinator, PipelineDumpable @CoordinatorScope class NotifCoordinatorsImpl @Inject constructor( - sectionStyleProvider: SectionStyleProvider, - dataStoreCoordinator: DataStoreCoordinator, - hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator, - hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator, - keyguardCoordinator: KeyguardCoordinator, - rankingCoordinator: RankingCoordinator, - appOpsCoordinator: AppOpsCoordinator, - deviceProvisionedCoordinator: DeviceProvisionedCoordinator, - bubbleCoordinator: BubbleCoordinator, - headsUpCoordinator: HeadsUpCoordinator, - gutsCoordinator: GutsCoordinator, - conversationCoordinator: ConversationCoordinator, - debugModeCoordinator: DebugModeCoordinator, - groupCountCoordinator: GroupCountCoordinator, - groupWhenCoordinator: GroupWhenCoordinator, - mediaCoordinator: MediaCoordinator, - preparationCoordinator: PreparationCoordinator, - remoteInputCoordinator: RemoteInputCoordinator, - rowAppearanceCoordinator: RowAppearanceCoordinator, - stackCoordinator: StackCoordinator, - shadeEventCoordinator: ShadeEventCoordinator, - smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator, - viewConfigCoordinator: ViewConfigCoordinator, - visualStabilityCoordinator: VisualStabilityCoordinator, - sensitiveContentCoordinator: SensitiveContentCoordinator, - dismissibilityCoordinator: DismissibilityCoordinator, + sectionStyleProvider: SectionStyleProvider, + featureFlags: FeatureFlags, + dataStoreCoordinator: DataStoreCoordinator, + hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator, + hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator, + keyguardCoordinator: KeyguardCoordinator, + rankingCoordinator: RankingCoordinator, + appOpsCoordinator: AppOpsCoordinator, + deviceProvisionedCoordinator: DeviceProvisionedCoordinator, + bubbleCoordinator: BubbleCoordinator, + headsUpCoordinator: HeadsUpCoordinator, + gutsCoordinator: GutsCoordinator, + conversationCoordinator: ConversationCoordinator, + debugModeCoordinator: DebugModeCoordinator, + groupCountCoordinator: GroupCountCoordinator, + groupWhenCoordinator: GroupWhenCoordinator, + mediaCoordinator: MediaCoordinator, + preparationCoordinator: PreparationCoordinator, + remoteInputCoordinator: RemoteInputCoordinator, + rowAppearanceCoordinator: RowAppearanceCoordinator, + stackCoordinator: StackCoordinator, + shadeEventCoordinator: ShadeEventCoordinator, + smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator, + viewConfigCoordinator: ViewConfigCoordinator, + visualStabilityCoordinator: VisualStabilityCoordinator, + sensitiveContentCoordinator: SensitiveContentCoordinator, + dismissibilityCoordinator: DismissibilityCoordinator, + dreamCoordinator: DreamCoordinator, ) : NotifCoordinators { private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList() @@ -96,6 +100,10 @@ class NotifCoordinatorsImpl @Inject constructor( mCoordinators.add(remoteInputCoordinator) mCoordinators.add(dismissibilityCoordinator) + if (featureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) { + mCoordinators.add(dreamCoordinator) + } + // Manually add Ordered Sections mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp mOrderedSections.add(appOpsCoordinator.sectioner) // ForegroundService 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 189608072ec7..9ecf50ee4f8c 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 @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.collection.inflation; -import static com.android.systemui.flags.Flags.NOTIFICATION_INLINE_REPLY_ANIMATION; 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; @@ -176,8 +175,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { entry.setRow(row); mNotifBindPipeline.manageRow(entry, row); mPresenter.onBindRow(row); - row.setInlineReplyAnimationFlagEnabled( - mFeatureFlags.isEnabled(NOTIFICATION_INLINE_REPLY_ANIMATION)); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 908c11a1d076..36a8e9833d39 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -566,7 +566,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView @Override public float getTopCornerRadius() { - if (isNewHeadsUpAnimFlagEnabled()) { + if (mImprovedHunAnimation.isEnabled()) { return super.getTopCornerRadius(); } @@ -576,7 +576,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView @Override public float getBottomCornerRadius() { - if (isNewHeadsUpAnimFlagEnabled()) { + if (mImprovedHunAnimation.isEnabled()) { return super.getBottomCornerRadius(); } 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 b34c28163abb..42b99a1dc68c 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 @@ -77,6 +77,7 @@ import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; @@ -275,7 +276,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private OnExpandClickListener mOnExpandClickListener; private View.OnClickListener mOnFeedbackClickListener; private Path mExpandingClipPath; - private boolean mIsInlineReplyAnimationFlagEnabled = false; + private final ViewRefactorFlag mInlineReplyAnimation = + new ViewRefactorFlag(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION); // Listener will be called when receiving a long click event. // Use #setLongPressPosition to optionally assign positional data with the long press. @@ -3121,10 +3123,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return showingLayout != null && showingLayout.requireRowToHaveOverlappingRendering(); } - public void setInlineReplyAnimationFlagEnabled(boolean isEnabled) { - mIsInlineReplyAnimationFlagEnabled = isEnabled; - } - @Override public void setActualHeight(int height, boolean notifyListeners) { boolean changed = height != getActualHeight(); @@ -3144,7 +3142,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } int contentHeight = Math.max(getMinHeight(), height); for (NotificationContentView l : mLayouts) { - if (mIsInlineReplyAnimationFlagEnabled) { + if (mInlineReplyAnimation.isEnabled()) { l.setContentHeight(height); } else { l.setContentHeight(contentHeight); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java index 7f23c1b89b51..c8f13a6302cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java @@ -28,10 +28,9 @@ import android.util.IndentingPrintWriter; import android.view.View; import android.view.ViewOutlineProvider; -import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.statusbar.notification.RoundableState; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.util.DumpUtilsKt; @@ -50,7 +49,8 @@ public abstract class ExpandableOutlineView extends ExpandableView { private float mOutlineAlpha = -1f; private boolean mAlwaysRoundBothCorners; private Path mTmpPath = new Path(); - private final FeatureFlags mFeatureFlags; + protected final ViewRefactorFlag mImprovedHunAnimation = + new ViewRefactorFlag(Flags.IMPROVED_HUN_ANIMATIONS); /** * {@code false} if the children views of the {@link ExpandableOutlineView} are translated when @@ -126,7 +126,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { return EMPTY_PATH; } float bottomRadius = mAlwaysRoundBothCorners ? getMaxRadius() : getBottomCornerRadius(); - if (!isNewHeadsUpAnimFlagEnabled() && (topRadius + bottomRadius > height)) { + if (!mImprovedHunAnimation.isEnabled() && (topRadius + bottomRadius > height)) { float overShoot = topRadius + bottomRadius - height; float currentTopRoundness = getTopRoundness(); float currentBottomRoundness = getBottomRoundness(); @@ -167,7 +167,6 @@ public abstract class ExpandableOutlineView extends ExpandableView { super(context, attrs); setOutlineProvider(mProvider); initDimens(); - mFeatureFlags = Dependency.get(FeatureFlags.class); } @Override @@ -376,8 +375,4 @@ public abstract class ExpandableOutlineView extends ExpandableView { }); } - // TODO(b/290365128) replace with ViewRefactorFlag - protected boolean isNewHeadsUpAnimFlagEnabled() { - return mFeatureFlags.isEnabled(Flags.IMPROVED_HUN_ANIMATIONS); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java index b2a3780c1024..867e08b2e743 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import dagger.Binds; import dagger.Module; @@ -58,9 +59,13 @@ public abstract class NotificationRowModule { @ElementsIntoSet @Named(NOTIF_REMOTEVIEWS_FACTORIES) static Set<NotifRemoteViewsFactory> provideNotifRemoteViewsFactories( - FeatureFlags featureFlags + FeatureFlags featureFlags, + PrecomputedTextViewFactory precomputedTextViewFactory ) { final Set<NotifRemoteViewsFactory> replacementFactories = new HashSet<>(); + if (featureFlags.isEnabled(Flags.PRECOMPUTED_TEXT)) { + replacementFactories.add(precomputedTextViewFactory); + } return replacementFactories; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt new file mode 100644 index 000000000000..b0023305ecdd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PrecomputedTextViewFactory.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.TextView +import com.android.internal.widget.ImageFloatingTextView +import javax.inject.Inject + +class PrecomputedTextViewFactory @Inject constructor() : NotifRemoteViewsFactory { + override fun instantiate( + parent: View?, + name: String, + context: Context, + attrs: AttributeSet + ): View? { + return when (name) { + TextView::class.java.name, + TextView::class.java.simpleName -> PrecomputedTextView(context, attrs) + ImageFloatingTextView::class.java.name -> + PrecomputedImageFloatingTextView(context, attrs) + else -> null + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt index 23a58d252ba6..22a87a7c9432 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt @@ -21,7 +21,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl @@ -66,7 +65,7 @@ class NotificationShelfViewBinderWrapperControllerImpl @Inject constructor() : override fun setOnClickListener(listener: View.OnClickListener) = unsupported private val unsupported: Nothing - get() = NotificationShelfController.throwIllegalFlagStateError(expected = true) + get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled") } /** Binds a [NotificationShelf] to its [view model][NotificationShelfViewModel]. */ @@ -80,8 +79,6 @@ object NotificationShelfViewBinder { ) { ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager) shelf.apply { - setRefactorFlagEnabled(true) - setSensitiveRevealAnimEnabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)) // TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind() notificationIconAreaController.setShelfIcons(shelfIcons) repeatWhenAttached { 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 b0f3f598cb91..95e74f210c5d 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 @@ -29,7 +29,6 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarState; @@ -57,7 +56,6 @@ public class AmbientState implements Dumpable { private final SectionProvider mSectionProvider; private final BypassController mBypassController; private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator; - private final FeatureFlags mFeatureFlags; /** * Used to read bouncer states. */ @@ -261,13 +259,12 @@ public class AmbientState implements Dumpable { @NonNull SectionProvider sectionProvider, @NonNull BypassController bypassController, @Nullable StatusBarKeyguardViewManager statusBarKeyguardViewManager, - @NonNull LargeScreenShadeInterpolator largeScreenShadeInterpolator, - @NonNull FeatureFlags featureFlags) { + @NonNull LargeScreenShadeInterpolator largeScreenShadeInterpolator + ) { mSectionProvider = sectionProvider; mBypassController = bypassController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mLargeScreenShadeInterpolator = largeScreenShadeInterpolator; - mFeatureFlags = featureFlags; reload(context); dumpManager.registerDumpable(this); } @@ -753,10 +750,6 @@ public class AmbientState implements Dumpable { return mLargeScreenShadeInterpolator; } - public FeatureFlags getFeatureFlags() { - return mFeatureFlags; - } - @Override public void dump(PrintWriter pw, String[] args) { pw.println("mTopPadding=" + mTopPadding); 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 c1ceb3ce5ab6..d71bc2fd6470 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 @@ -89,6 +89,7 @@ import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.shade.ShadeController; @@ -198,7 +199,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private Set<Integer> mDebugTextUsedYPositions; private final boolean mDebugRemoveAnimation; private final boolean mSensitiveRevealAnimEndabled; - private boolean mAnimatedInsets; + private final ViewRefactorFlag mAnimatedInsets; + private final ViewRefactorFlag mShelfRefactor; private int mContentHeight; private float mIntrinsicContentHeight; @@ -621,7 +623,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES); mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION); mSensitiveRevealAnimEndabled = featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM); - setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS)); + mAnimatedInsets = + new ViewRefactorFlag(featureFlags, Flags.ANIMATED_NOTIFICATION_SHADE_INSETS); + mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR); mSectionsManager = Dependency.get(NotificationSectionsManager.class); mScreenOffAnimationController = Dependency.get(ScreenOffAnimationController.class); @@ -660,7 +664,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mGroupMembershipManager = Dependency.get(GroupMembershipManager.class); mGroupExpansionManager = Dependency.get(GroupExpansionManager.class); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - if (mAnimatedInsets) { + if (mAnimatedInsets.isEnabled()) { setWindowInsetsAnimationCallback(mInsetsCallback); } } @@ -730,11 +734,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } @VisibleForTesting - void setAnimatedInsetsEnabled(boolean enabled) { - mAnimatedInsets = enabled; - } - - @VisibleForTesting public void updateFooter() { if (mFooterView == null) { return; @@ -1773,7 +1772,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return; } mForcedScroll = v; - if (mAnimatedInsets) { + if (mAnimatedInsets.isEnabled()) { updateForcedScroll(); } else { scrollTo(v); @@ -1822,7 +1821,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - if (!mAnimatedInsets) { + if (!mAnimatedInsets.isEnabled()) { mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom; } mWaterfallTopInset = 0; @@ -1830,11 +1829,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (cutout != null) { mWaterfallTopInset = cutout.getWaterfallInsets().top; } - if (mAnimatedInsets && !mIsInsetAnimationRunning) { + if (mAnimatedInsets.isEnabled() && !mIsInsetAnimationRunning) { // update bottom inset e.g. after rotation updateBottomInset(insets); } - if (!mAnimatedInsets) { + if (!mAnimatedInsets.isEnabled()) { int range = getScrollRange(); if (mOwnScrollY > range) { // HACK: We're repeatedly getting staggered insets here while the IME is @@ -2714,7 +2713,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * @param listener callback for notification removed */ public void setOnNotificationRemovedListener(OnNotificationRemovedListener listener) { - NotificationShelfController.assertRefactorFlagDisabled(mAmbientState.getFeatureFlags()); + mShelfRefactor.assertDisabled(); mOnNotificationRemovedListener = listener; } @@ -2727,7 +2726,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (!mChildTransferInProgress) { onViewRemovedInternal(expandableView, this); } - if (mAmbientState.getFeatureFlags().isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + if (mShelfRefactor.isEnabled()) { mShelf.requestRoundnessResetFor(expandableView); } else { if (mOnNotificationRemovedListener != null) { @@ -4943,18 +4942,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @Nullable public ExpandableView getShelf() { - if (NotificationShelfController.checkRefactorFlagEnabled(mAmbientState.getFeatureFlags())) { - return mShelf; - } else { - return null; - } + if (!mShelfRefactor.expectEnabled()) return null; + return mShelf; } public void setShelf(NotificationShelf shelf) { - if (!NotificationShelfController.checkRefactorFlagEnabled( - mAmbientState.getFeatureFlags())) { - return; - } + if (!mShelfRefactor.expectEnabled()) return; int index = -1; if (mShelf != null) { index = indexOfChild(mShelf); @@ -4968,7 +4961,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } public void setShelfController(NotificationShelfController notificationShelfController) { - NotificationShelfController.assertRefactorFlagDisabled(mAmbientState.getFeatureFlags()); + mShelfRefactor.assertDisabled(); int index = -1; if (mShelf != null) { index = indexOfChild(mShelf); 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 ef7375aa690b..4668aa433533 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 @@ -65,6 +65,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.shared.model.KeyguardState; @@ -205,6 +206,7 @@ public class NotificationStackScrollLayoutController { private boolean mIsInTransitionToAod = false; private final FeatureFlags mFeatureFlags; + private final ViewRefactorFlag mShelfRefactor; private final NotificationTargetsHelper mNotificationTargetsHelper; private final SecureSettings mSecureSettings; private final NotificationDismissibilityProvider mDismissibilityProvider; @@ -718,6 +720,7 @@ public class NotificationStackScrollLayoutController { mShadeController = shadeController; mNotifIconAreaController = notifIconAreaController; mFeatureFlags = featureFlags; + mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR); mNotificationTargetsHelper = notificationTargetsHelper; mSecureSettings = secureSettings; mDismissibilityProvider = dismissibilityProvider; @@ -1432,7 +1435,7 @@ public class NotificationStackScrollLayoutController { } public void setShelfController(NotificationShelfController notificationShelfController) { - NotificationShelfController.assertRefactorFlagDisabled(mFeatureFlags); + mShelfRefactor.assertDisabled(); mView.setShelfController(notificationShelfController); } @@ -1645,12 +1648,12 @@ public class NotificationStackScrollLayoutController { } public void setShelf(NotificationShelf shelf) { - if (!NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) return; + if (!mShelfRefactor.expectEnabled()) return; mView.setShelf(shelf); } public int getShelfHeight() { - if (!NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) { + if (!mShelfRefactor.expectEnabled()) { return 0; } ExpandableView shelf = mView.getShelf(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 2d8f371aadac..1f9c9f2b8c14 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -160,6 +160,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private KeyguardViewController mKeyguardViewController; private DozeScrimController mDozeScrimController; private KeyguardViewMediator mKeyguardViewMediator; + private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private PendingAuthenticated mPendingAuthenticated = null; private boolean mHasScreenTurnedOnSinceAuthenticating; private boolean mFadedAwayAfterWakeAndUnlock; @@ -280,7 +281,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp LatencyTracker latencyTracker, ScreenOffAnimationController screenOffAnimationController, VibratorHelper vibrator, - SystemClock systemClock + SystemClock systemClock, + StatusBarKeyguardViewManager statusBarKeyguardViewManager ) { mPowerManager = powerManager; mUpdateMonitor = keyguardUpdateMonitor; @@ -308,6 +310,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp mVibratorHelper = vibrator; mLogger = biometricUnlockLogger; mSystemClock = systemClock; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; dumpManager.registerDumpable(getClass().getName(), this); } @@ -449,8 +452,19 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp // During wake and unlock, we need to draw black before waking up to avoid abrupt // brightness changes due to display state transitions. Runnable wakeUp = ()-> { - if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) { + // Check to see if we are still locked when we are waking and unlocking from dream. + // This runnable should be executed after unlock. If that's true, we could be not + // dreaming, but still locked. In this case, we should attempt to authenticate instead + // of waking up. + if (mode == MODE_WAKE_AND_UNLOCK_FROM_DREAM + && !mKeyguardStateController.isUnlocked() + && !mUpdateMonitor.isDreaming()) { + // Post wakeUp runnable is called from a callback in keyguard. + mHandler.post(() -> mKeyguardViewController.notifyKeyguardAuthenticated( + false /* primaryAuth */)); + } else if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) { mLogger.i("bio wakelock: Authenticated, waking up..."); + mPowerManager.wakeUp( mSystemClock.uptimeMillis(), PowerManager.WAKE_REASON_BIOMETRIC, @@ -462,7 +476,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp Trace.endSection(); }; - if (mMode != MODE_NONE) { + if (mMode != MODE_NONE && mMode != MODE_WAKE_AND_UNLOCK_FROM_DREAM) { wakeUp.run(); } switch (mMode) { @@ -484,6 +498,10 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp Trace.endSection(); break; case MODE_WAKE_AND_UNLOCK_FROM_DREAM: + // In the case of waking and unlocking from dream, waking up is delayed until after + // unlock is complete to avoid conflicts during each sequence's transitions. + mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(wakeUp); + // Execution falls through here to proceed unlocking. case MODE_WAKE_AND_UNLOCK_PULSING: case MODE_WAKE_AND_UNLOCK: if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 2b9c3d33e9b8..acd6e49fe8c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -259,8 +259,6 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner { void readyForKeyguardDone(); - void setLockscreenUser(int newUserId); - void showKeyguard(); boolean hideKeyguard(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 0a7ee52fba46..8361d6ba1801 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -51,7 +51,6 @@ import android.app.PendingIntent; import android.app.StatusBarManager; import android.app.TaskInfo; import android.app.UiModeManager; -import android.app.WallpaperInfo; import android.app.WallpaperManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; @@ -413,7 +412,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final Point mCurrentDisplaySize = new Point(); - protected NotificationShadeWindowView mNotificationShadeWindowView; protected PhoneStatusBarView mStatusBarView; private PhoneStatusBarViewController mPhoneStatusBarViewController; private PhoneStatusBarTransitions mStatusBarTransitions; @@ -456,7 +454,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final FalsingManager mFalsingManager; private final BroadcastDispatcher mBroadcastDispatcher; private final ConfigurationController mConfigurationController; - protected NotificationShadeWindowViewController mNotificationShadeWindowViewController; + private final Lazy<NotificationShadeWindowViewController> + mNotificationShadeWindowViewControllerLazy; private final DozeParameters mDozeParameters; private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; private final CentralSurfacesComponent.Factory mCentralSurfacesComponentFactory; @@ -722,6 +721,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { Lazy<AssistManager> assistManagerLazy, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, + Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewControllerLazy, NotificationShelfController notificationShelfController, NotificationStackScrollLayoutController notificationStackScrollLayoutController, DozeParameters dozeParameters, @@ -825,6 +825,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mAssistManagerLazy = assistManagerLazy; mConfigurationController = configurationController; mNotificationShadeWindowController = notificationShadeWindowController; + mNotificationShadeWindowViewControllerLazy = notificationShadeWindowViewControllerLazy; mNotificationShelfController = notificationShelfController; mStackScrollerController = notificationStackScrollLayoutController; mStackScroller = mStackScrollerController.getView(); @@ -978,16 +979,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { createAndAddWindows(result); - if (mWallpaperSupported) { - // Make sure we always have the most current wallpaper info. - IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); - mBroadcastDispatcher.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter, - null /* handler */, UserHandle.ALL); - mWallpaperChangedReceiver.onReceive(mContext, null); - } else if (DEBUG) { - Log.v(TAG, "start(): no wallpaper service "); - } - // Set up the initial notification state. This needs to happen before CommandQueue.disable() setUpPresenter(); @@ -1073,7 +1064,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mDozeServiceHost.initialize( this, mStatusBarKeyguardViewManager, - mNotificationShadeWindowViewController, + getNotificationShadeWindowViewController(), mShadeSurface, mAmbientIndicationContainer); updateLightRevealScrimVisibility(); @@ -1235,8 +1226,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { updateTheme(); inflateStatusBarWindow(); - mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener()); - mWallpaperController.setRootView(mNotificationShadeWindowView); + getNotificationShadeWindowView().setOnTouchListener(getStatusBarWindowTouchListener()); + mWallpaperController.setRootView(getNotificationShadeWindowView()); // TODO: Deal with the ugliness that comes from having some of the status bar broken out // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. @@ -1257,7 +1248,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mStatusBarView = statusBarView; mPhoneStatusBarViewController = statusBarViewController; mStatusBarTransitions = statusBarTransitions; - mNotificationShadeWindowViewController + getNotificationShadeWindowViewController() .setStatusBarViewController(mPhoneStatusBarViewController); // Ensure we re-propagate panel expansion values to the panel controller and // any listeners it may have, such as PanelBar. This will also ensure we @@ -1271,7 +1262,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mStatusBarInitializer.initializeStatusBar( mCentralSurfacesComponent::createCollapsedStatusBarFragment); - mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView); + mStatusBarTouchableRegionManager.setup(this, getNotificationShadeWindowView()); createNavigationBar(result); @@ -1279,7 +1270,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mLockscreenWallpaper = mLockscreenWallpaperLazy.get(); } - mAmbientIndicationContainer = mNotificationShadeWindowView.findViewById( + mAmbientIndicationContainer = getNotificationShadeWindowView().findViewById( R.id.ambient_indication_container); mAutoHideController.setStatusBar(new AutoHideUiElement() { @@ -1304,10 +1295,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } }); - ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind); - ScrimView notificationsScrim = mNotificationShadeWindowView + ScrimView scrimBehind = getNotificationShadeWindowView().findViewById(R.id.scrim_behind); + ScrimView notificationsScrim = getNotificationShadeWindowView() .findViewById(R.id.scrim_notifications); - ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front); + ScrimView scrimInFront = getNotificationShadeWindowView().findViewById(R.id.scrim_in_front); mScrimController.setScrimVisibleListener(scrimsVisible -> { mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible); @@ -1345,7 +1336,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mNotificationShelfController, mHeadsUpManager); - BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop); + BackDropView backdrop = getNotificationShadeWindowView().findViewById(R.id.backdrop); if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) { mMediaManager.setup(null, null, null, mScrimController, null); } else { @@ -1364,7 +1355,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }); // Set up the quick settings tile panel - final View container = mNotificationShadeWindowView.findViewById(R.id.qs_frame); + final View container = getNotificationShadeWindowView().findViewById(R.id.qs_frame); if (container != null) { FragmentHostManager fragmentHostManager = mFragmentService.getFragmentHostManager(container); @@ -1379,7 +1370,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { .withDefault(this::createDefaultQSFragment) .build()); mBrightnessMirrorController = new BrightnessMirrorController( - mNotificationShadeWindowView, + getNotificationShadeWindowView(), mShadeSurface, mNotificationShadeDepthControllerLazy.get(), mBrightnessSliderFactory, @@ -1396,7 +1387,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }); } - mReportRejectedTouch = mNotificationShadeWindowView + mReportRejectedTouch = getNotificationShadeWindowView() .findViewById(R.id.report_rejected_touch); if (mReportRejectedTouch != null) { updateReportRejectedTouchVisibility(); @@ -1544,7 +1535,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { protected QS createDefaultQSFragment() { return mFragmentService - .getFragmentHostManager(mNotificationShadeWindowView) + .getFragmentHostManager(getNotificationShadeWindowView()) .create(QSFragment.class); } @@ -1553,7 +1544,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mActivityLaunchAnimator.setCallback(mActivityLaunchAnimatorCallback); mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener); mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider( - mNotificationShadeWindowViewController, + getNotificationShadeWindowViewController(), mNotifListContainer, mHeadsUpManager, mJankMonitor); @@ -1592,7 +1583,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mAutoHideController.checkUserAutoHide(event); mRemoteInputManager.checkRemoteInputOutside(event); mShadeController.onStatusBarTouch(event); - return mNotificationShadeWindowView.onTouchEvent(event); + return getNotificationShadeWindowView().onTouchEvent(event); }; } @@ -1606,15 +1597,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mCentralSurfacesComponent::createCollapsedStatusBarFragment); ViewGroup windowRootView = mCentralSurfacesComponent.getWindowRootView(); - mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView(); - mNotificationShadeWindowViewController = mCentralSurfacesComponent - .getNotificationShadeWindowViewController(); // TODO(b/277762009): Inject [NotificationShadeWindowView] directly into the controller. // (Right now, there's a circular dependency.) mNotificationShadeWindowController.setWindowRootView(windowRootView); - mNotificationShadeWindowViewController.setupExpandedStatusBar(); + getNotificationShadeWindowViewController().setupExpandedStatusBar(); mShadeController.setNotificationShadeWindowViewController( - mNotificationShadeWindowViewController); + getNotificationShadeWindowViewController()); mBackActionInteractor.setup(mQsController, mShadeSurface); mPresenter = mCentralSurfacesComponent.getNotificationPresenter(); mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter(); @@ -1633,6 +1621,14 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mCommandQueue.addCallback(mCommandQueueCallbacks); } + protected NotificationShadeWindowViewController getNotificationShadeWindowViewController() { + return mNotificationShadeWindowViewControllerLazy.get(); + } + + protected NotificationShadeWindowView getNotificationShadeWindowView() { + return getNotificationShadeWindowViewController().getView(); + } + protected void startKeyguard() { Trace.beginSection("CentralSurfaces#startKeyguard"); mStatusBarStateController.addCallback(mStateListener, @@ -1688,7 +1684,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public AuthKeyguardMessageArea getKeyguardMessageArea() { - return mNotificationShadeWindowViewController.getKeyguardMessageArea(); + return getNotificationShadeWindowViewController().getKeyguardMessageArea(); } @Override @@ -1982,11 +1978,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { pw.print(" mWallpaperSupported= "); pw.println(mWallpaperSupported); pw.println(" ShadeWindowView: "); - if (mNotificationShadeWindowViewController != null) { - mNotificationShadeWindowViewController.dump(pw, args); - CentralSurfaces.dumpBarTransitions( - pw, "PhoneStatusBarTransitions", mStatusBarTransitions); - } + getNotificationShadeWindowViewController().dump(pw, args); + CentralSurfaces.dumpBarTransitions( + pw, "PhoneStatusBarTransitions", mStatusBarTransitions); pw.println(" mMediaManager: "); if (mMediaManager != null) { @@ -2159,18 +2153,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }; /** - * Notify the shade controller that the current user changed - * - * @param newUserId userId of the new user - */ - @Override - public void setLockscreenUser(int newUserId) { - if (mWallpaperSupported) { - mWallpaperChangedReceiver.onReceive(mContext, null); - } - } - - /** * Reload some of our resources when the configuration changes. * * We don't reload everything when the configuration changes -- we probably @@ -2860,7 +2842,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { updateVisibleToUser(); updateNotificationPanelTouchState(); - mNotificationShadeWindowViewController.cancelCurrentTouch(); + getNotificationShadeWindowViewController().cancelCurrentTouch(); if (mLaunchCameraOnFinishedGoingToSleep) { mLaunchCameraOnFinishedGoingToSleep = false; @@ -3172,12 +3154,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { updateScrimController(); } - @VisibleForTesting - public void setNotificationShadeWindowViewController( - NotificationShadeWindowViewController nswvc) { - mNotificationShadeWindowViewController = nswvc; - } - /** * Set the amount of progress we are currently in if we're transitioning to the full shade. * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full @@ -3412,7 +3388,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mVisible = visible; if (visible) { DejankUtils.notifyRendererOfExpensiveFrame( - mNotificationShadeWindowView, "onShadeVisibilityChanged"); + getNotificationShadeWindowView(), "onShadeVisibilityChanged"); } else { mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */); @@ -3550,33 +3526,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } }; - /** - * @deprecated See {@link com.android.systemui.wallpapers.data.repository.WallpaperRepository} - * instead. - */ - private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!mWallpaperSupported) { - // Receiver should not have been registered at all... - Log.wtf(TAG, "WallpaperManager not supported"); - return; - } - WallpaperInfo info = mWallpaperManager.getWallpaperInfoForUser( - mUserTracker.getUserId()); - mWallpaperController.onWallpaperInfoUpdated(info); - - final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_dozeSupportsAodWallpaper); - // If WallpaperInfo is null, it must be ImageWallpaper. - final boolean supportsAmbientMode = deviceSupportsAodWallpaper - && (info != null && info.supportsAmbientMode()); - - mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); - mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode); - } - }; - private final ConfigurationListener mConfigurationListener = new ConfigurationListener() { @Override public void onConfigChanged(Configuration newConfig) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 7312db6595e5..ed9722e04da0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -311,6 +311,7 @@ public final class DozeServiceHost implements DozeHost { @Override public void dozeTimeTick() { + mDozeInteractor.dozeTimeTick(); mNotificationPanel.dozeTimeTick(); mAuthController.dozeTimeTick(); if (mAmbientIndicationContainer instanceof DozeReceiver) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index ff1b31d8848f..924aac4e70be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -50,12 +50,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr @DevicePostureInt private var postureState: Int = DEVICE_POSTURE_UNKNOWN private var pendingUnlock: PendingUnlock? = null private val listeners = mutableListOf<OnBypassStateChangedListener>() - private val postureCallback = DevicePostureController.Callback { posture -> - if (postureState != posture) { - postureState = posture - notifyListeners() - } - } private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback { override fun onFaceAuthEnabledChanged() = notifyListeners() } @@ -162,10 +156,8 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr val dismissByDefault = if (context.resources.getBoolean( com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0 - tunerService.addTunable(object : TunerService.Tunable { - override fun onTuningChanged(key: String?, newValue: String?) { - bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0 - } + tunerService.addTunable({ key, _ -> + bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0 }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD) lockscreenUserManager.addUserChangedListener( object : NotificationLockscreenUserManager.UserChangedListener { @@ -281,8 +273,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr } companion object { - const val BYPASS_FADE_DURATION = 67 - private const val FACE_UNLOCK_BYPASS_NO_OVERRIDE = 0 private const val FACE_UNLOCK_BYPASS_ALWAYS = 1 private const val FACE_UNLOCK_BYPASS_NEVER = 2 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index e18c9d86d74b..0bf0f4b504b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -24,6 +24,8 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.demomode.DemoMode; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; +import com.android.systemui.flags.ViewRefactorFlag; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -88,7 +90,7 @@ public class NotificationIconAreaController implements private final ArrayList<Rect> mTintAreas = new ArrayList<>(); private final Context mContext; - private final FeatureFlags mFeatureFlags; + private final ViewRefactorFlag mShelfRefactor; private int mAodIconAppearTranslation; @@ -120,12 +122,13 @@ public class NotificationIconAreaController implements Optional<Bubbles> bubblesOptional, DemoModeController demoModeController, DarkIconDispatcher darkIconDispatcher, - FeatureFlags featureFlags, StatusBarWindowController statusBarWindowController, + FeatureFlags featureFlags, + StatusBarWindowController statusBarWindowController, ScreenOffAnimationController screenOffAnimationController) { mContrastColorUtil = ContrastColorUtil.getInstance(context); mContext = context; mStatusBarStateController = statusBarStateController; - mFeatureFlags = featureFlags; + mShelfRefactor = new ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR); mStatusBarStateController.addCallback(this); mMediaManager = notificationMediaManager; mDozeParameters = dozeParameters; @@ -179,12 +182,12 @@ public class NotificationIconAreaController implements } public void setupShelf(NotificationShelfController notificationShelfController) { - NotificationShelfController.assertRefactorFlagDisabled(mFeatureFlags); + mShelfRefactor.assertDisabled(); mShelfIcons = notificationShelfController.getShelfIcons(); } public void setShelfIcons(NotificationIconContainer icons) { - if (NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) { + if (mShelfRefactor.expectEnabled()) { mShelfIcons = icons; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index f0fc1432c5a3..862f169b2176 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -30,6 +30,7 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.shade.ShadeController import com.android.systemui.shade.ShadeLogger +import com.android.systemui.shade.ShadeViewController import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.unfold.SysUIUnfoldComponent @@ -51,6 +52,7 @@ class PhoneStatusBarViewController private constructor( @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?, private val centralSurfaces: CentralSurfaces, private val shadeController: ShadeController, + private val shadeViewController: ShadeViewController, private val shadeLogger: ShadeLogger, private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, private val userChipViewModel: StatusBarUserChipViewModel, @@ -165,20 +167,20 @@ class PhoneStatusBarViewController private constructor( if (event.action == MotionEvent.ACTION_DOWN) { // If the view that would receive the touch is disabled, just have status // bar eat the gesture. - if (!centralSurfaces.shadeViewController.isViewEnabled) { + if (!shadeViewController.isViewEnabled) { shadeLogger.logMotionEvent(event, "onTouchForwardedFromStatusBar: panel view disabled") return true } - if (centralSurfaces.shadeViewController.isFullyCollapsed && + if (shadeViewController.isFullyCollapsed && event.y < 1f) { // b/235889526 Eat events on the top edge of the phone when collapsed shadeLogger.logMotionEvent(event, "top edge touch ignored") return true } - centralSurfaces.shadeViewController.startTrackingExpansionFromStatusBar() + shadeViewController.startTrackingExpansionFromStatusBar() } - return centralSurfaces.shadeViewController.handleExternalTouch(event) + return shadeViewController.handleExternalTouch(event) } } @@ -222,6 +224,7 @@ class PhoneStatusBarViewController private constructor( private val userChipViewModel: StatusBarUserChipViewModel, private val centralSurfaces: CentralSurfaces, private val shadeController: ShadeController, + private val shadeViewController: ShadeViewController, private val shadeLogger: ShadeLogger, private val viewUtil: ViewUtil, private val configurationController: ConfigurationController, @@ -241,6 +244,7 @@ class PhoneStatusBarViewController private constructor( progressProvider.getOrNull(), centralSurfaces, shadeController, + shadeViewController, shadeLogger, statusBarMoveFromCenterAnimationController, userChipViewModel, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java index 481cf3ceb197..9a295e63fb9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java @@ -21,6 +21,7 @@ import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.window.StatusBarWindowController; @@ -35,6 +36,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener private final NotificationShadeWindowController mNotificationShadeWindowController; private final StatusBarWindowController mStatusBarWindowController; private final ShadeViewController mShadeViewController; + private final NotificationStackScrollLayoutController mNsslController; private final KeyguardBypassController mKeyguardBypassController; private final HeadsUpManagerPhone mHeadsUpManager; private final StatusBarStateController mStatusBarStateController; @@ -45,14 +47,15 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener NotificationShadeWindowController notificationShadeWindowController, StatusBarWindowController statusBarWindowController, ShadeViewController shadeViewController, + NotificationStackScrollLayoutController nsslController, KeyguardBypassController keyguardBypassController, HeadsUpManagerPhone headsUpManager, StatusBarStateController statusBarStateController, NotificationRemoteInputManager notificationRemoteInputManager) { - mNotificationShadeWindowController = notificationShadeWindowController; mStatusBarWindowController = statusBarWindowController; mShadeViewController = shadeViewController; + mNsslController = nsslController; mKeyguardBypassController = keyguardBypassController; mHeadsUpManager = headsUpManager; mStatusBarStateController = statusBarStateController; @@ -85,8 +88,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener //animation // is finished. mHeadsUpManager.setHeadsUpGoingAway(true); - mShadeViewController.getNotificationStackScrollLayoutController() - .runAfterAnimationFinished(() -> { + mNsslController.runAfterAnimationFinished(() -> { if (!mHeadsUpManager.hasPinnedHeadsUp()) { mNotificationShadeWindowController.setHeadsUpShowing(false); mHeadsUpManager.setHeadsUpGoingAway(false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 35285b222f63..ad8530df0523 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -28,7 +28,6 @@ import android.service.vr.IVrStateCallbacks; import android.util.Log; import android.util.Slog; import android.view.View; -import android.view.accessibility.AccessibilityManager; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.InitController; @@ -50,7 +49,6 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor; @@ -59,7 +57,6 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; -import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; @@ -78,21 +75,17 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu private final NotifShadeEventSource mNotifShadeEventSource; private final NotificationMediaManager mMediaManager; private final NotificationGutsManager mGutsManager; - private final ShadeViewController mNotificationPanel; private final HeadsUpManagerPhone mHeadsUpManager; private final AboveShelfObserver mAboveShelfObserver; private final DozeScrimController mDozeScrimController; - private final CentralSurfaces mCentralSurfaces; private final NotificationsInteractor mNotificationsInteractor; + private final NotificationStackScrollLayoutController mNsslController; private final LockscreenShadeTransitionController mShadeTransitionController; private final PowerInteractor mPowerInteractor; private final CommandQueue mCommandQueue; - - private final AccessibilityManager mAccessibilityManager; private final KeyguardManager mKeyguardManager; private final NotificationShadeWindowController mNotificationShadeWindowController; - private final NotifPipelineFlags mNotifPipelineFlags; private final IStatusBarService mBarService; private final DynamicPrivacyController mDynamicPrivacyController; private final NotificationListContainer mNotifListContainer; @@ -113,7 +106,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu NotificationShadeWindowController notificationShadeWindowController, DynamicPrivacyController dynamicPrivacyController, KeyguardStateController keyguardStateController, - CentralSurfaces centralSurfaces, NotificationsInteractor notificationsInteractor, LockscreenShadeTransitionController shadeTransitionController, PowerInteractor powerInteractor, @@ -123,11 +115,9 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu NotifShadeEventSource notifShadeEventSource, NotificationMediaManager notificationMediaManager, NotificationGutsManager notificationGutsManager, - LockscreenGestureLogger lockscreenGestureLogger, InitController initController, NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationRemoteInputManager remoteInputManager, - NotifPipelineFlags notifPipelineFlags, NotificationRemoteInputManager.Callback remoteInputManagerCallback, NotificationListContainer notificationListContainer) { mActivityStarter = activityStarter; @@ -136,9 +126,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu mQsController = quickSettingsController; mHeadsUpManager = headsUp; mDynamicPrivacyController = dynamicPrivacyController; - // TODO: use KeyguardStateController#isOccluded to remove this dependency - mCentralSurfaces = centralSurfaces; mNotificationsInteractor = notificationsInteractor; + mNsslController = stackScrollerController; mShadeTransitionController = shadeTransitionController; mPowerInteractor = powerInteractor; mCommandQueue = commandQueue; @@ -149,10 +138,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu mGutsManager = notificationGutsManager; mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView()); mNotificationShadeWindowController = notificationShadeWindowController; - mNotifPipelineFlags = notifPipelineFlags; mAboveShelfObserver.setListener(statusBarWindow.findViewById( R.id.notification_container_parent)); - mAccessibilityManager = context.getSystemService(AccessibilityManager.class); mDozeScrimController = dozeScrimController; mKeyguardManager = context.getSystemService(KeyguardManager.class); mBarService = IStatusBarService.Stub.asInterface( @@ -170,7 +157,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu } remoteInputManager.setUpWithCallback( remoteInputManagerCallback, - mNotificationPanel.getShadeNotificationPresenter().createRemoteInputDelegate()); + mNsslController.createDelegate()); initController.addPostInitTask(() -> { mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied); @@ -202,7 +189,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu } private void maybeEndAmbientPulse() { - if (mNotificationPanel.getShadeNotificationPresenter().hasPulsingNotifications() + if (mNsslController.getNotificationListContainer().hasPulsingNotifications() && !mHeadsUpManager.hasNotifications()) { // We were showing a pulse for a notification, but no notifications are pulsing anymore. // Finish the pulse. @@ -217,7 +204,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu // End old BaseStatusBar.userSwitched mCommandQueue.animateCollapsePanels(); mMediaManager.clearCurrentMediaNotification(); - mCentralSurfaces.setLockscreenUser(newUserId); updateMediaMetaData(true, false); } @@ -272,22 +258,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu } }; - private final CheckSaveListener mCheckSaveListener = new CheckSaveListener() { - @Override - public void checkSave(Runnable saveImportance, StatusBarNotification sbn) { - // If the user has security enabled, show challenge if the setting is changed. - if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier()) - && mKeyguardManager.isKeyguardLocked()) { - onLockedNotificationImportanceChange(() -> { - saveImportance.run(); - return true; - }); - } else { - saveImportance.run(); - } - } - }; - private final OnSettingsClickListener mOnSettingsClickListener = new OnSettingsClickListener() { @Override public void onSettingsClick(String key) { @@ -309,7 +279,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu @Override public boolean suppressAwakeHeadsUp(NotificationEntry entry) { final StatusBarNotification sbn = entry.getSbn(); - if (mCentralSurfaces.isOccluded()) { + if (mKeyguardStateController.isOccluded()) { boolean devicePublic = mLockscreenUserManager .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId()); boolean userPublic = devicePublic diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java index 4ae460a3f0e1..e77f419f74e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java @@ -21,8 +21,6 @@ import static com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.ST import static java.lang.annotation.RetentionPolicy.RUNTIME; import com.android.systemui.scene.ui.view.WindowRootView; -import com.android.systemui.shade.NotificationShadeWindowView; -import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.ShadeHeaderController; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.notification.NotificationActivityStarter; @@ -77,16 +75,6 @@ public interface CentralSurfacesComponent { WindowRootView getWindowRootView(); /** - * Creates or returns a {@link NotificationShadeWindowView}. - */ - NotificationShadeWindowView getNotificationShadeWindowView(); - - /** - * Creates a NotificationShadeWindowViewController. - */ - NotificationShadeWindowViewController getNotificationShadeWindowViewController(); - - /** * Creates a StatusBarHeadsUpChangeListener. */ StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt index 27cc64f9a8e8..0e99c67a0d80 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt @@ -19,12 +19,10 @@ package com.android.systemui.statusbar.pipeline.dagger import android.net.wifi.WifiManager import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.TableLogBufferFactory -import com.android.systemui.log.LogBuffer -import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel -import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModelImpl import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel @@ -46,6 +44,8 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.Connectivi import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinderImpl +import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel +import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModelImpl import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositorySwitcher @@ -58,9 +58,9 @@ import dagger.Module import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap -import kotlinx.coroutines.flow.Flow import java.util.function.Supplier import javax.inject.Named +import kotlinx.coroutines.flow.Flow @Module abstract class StatusBarPipelineModule { diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index 5d09e064604a..a501e87902a8 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -20,6 +20,11 @@ import android.content.Intent; import com.android.systemui.Dependency; +/** + * @deprecated Don't use this class to listen to Secure Settings. Use {@code SecureSettings} instead + * or {@code SettingsObserver} to be able to specify the handler. + */ +@Deprecated public abstract class TunerService { public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER"; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index 8cfe2eac3d33..ccc0a79d2cfe 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -56,7 +56,11 @@ import javax.inject.Inject; /** + * @deprecated Don't use this class to listen to Secure Settings. Use {@code SecureSettings} instead + * or {@code SettingsObserver} to be able to specify the handler. + * This class will interact with SecureSettings using the main looper. */ +@Deprecated @SysUISingleton public class TunerServiceImpl extends TunerService { diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt index eed7950abacb..cbe402017c41 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt @@ -94,7 +94,7 @@ constructor( wakefulnessLifecycle.addObserver(this) // TODO(b/254878364): remove this call to NPVC.getView() - getShadeFoldAnimator().view.repeatWhenAttached { + getShadeFoldAnimator().view?.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { listenForDozing(this) } } } @@ -161,10 +161,9 @@ constructor( // but we should wait for the initial animation preparations to be drawn // (setting initial alpha/translation) // TODO(b/254878364): remove this call to NPVC.getView() - OneShotPreDrawListener.add( - getShadeFoldAnimator().view, - onReady - ) + getShadeFoldAnimator().view?.let { + OneShotPreDrawListener.add(it, onReady) + } } else { // No animation, call ready callback immediately onReady.run() diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt index db2aca873d0c..65a02184f96d 100644 --- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt +++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt @@ -16,32 +16,34 @@ package com.android.systemui.util -import android.app.WallpaperInfo import android.app.WallpaperManager import android.util.Log import android.view.View import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.wallpapers.data.repository.WallpaperRepository import javax.inject.Inject import kotlin.math.max private const val TAG = "WallpaperController" +/** + * Controller for wallpaper-related logic. + * + * Note: New logic should be added to [WallpaperRepository], not this class. + */ @SysUISingleton -class WallpaperController @Inject constructor(private val wallpaperManager: WallpaperManager) { +class WallpaperController @Inject constructor( + private val wallpaperManager: WallpaperManager, + private val wallpaperRepository: WallpaperRepository, +) { var rootView: View? = null private var notificationShadeZoomOut: Float = 0f private var unfoldTransitionZoomOut: Float = 0f - private var wallpaperInfo: WallpaperInfo? = null - - fun onWallpaperInfoUpdated(wallpaperInfo: WallpaperInfo?) { - this.wallpaperInfo = wallpaperInfo - } - private val shouldUseDefaultUnfoldTransition: Boolean - get() = wallpaperInfo?.shouldUseDefaultUnfoldTransition() + get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition() ?: true fun setNotificationShadeZoom(zoomOut: Float) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 349f3684659c..87b2697611d2 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -34,6 +34,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL; import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder; +import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION; import static com.android.systemui.volume.Events.DISMISS_REASON_POSTURE_CHANGED; import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED; @@ -82,6 +83,7 @@ import android.util.Slog; import android.util.SparseBooleanArray; import android.view.ContextThemeWrapper; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.View.AccessibilityDelegate; @@ -120,6 +122,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.VolumeDialog; @@ -300,6 +303,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private final DevicePostureController mDevicePostureController; private @DevicePostureController.DevicePostureInt int mDevicePosture; private int mOrientation; + private final FeatureFlags mFeatureFlags; public VolumeDialogImpl( Context context, @@ -315,7 +319,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, CsdWarningDialog.Factory csdWarningDialogFactory, DevicePostureController devicePostureController, Looper looper, - DumpManager dumpManager) { + DumpManager dumpManager, + FeatureFlags featureFlags) { + mFeatureFlags = featureFlags; mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); mHandler = new H(looper); @@ -1319,12 +1325,14 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private void provideTouchFeedbackH(int newRingerMode) { VibrationEffect effect = null; + int hapticConstant = HapticFeedbackConstants.NO_HAPTICS; switch (newRingerMode) { case RINGER_MODE_NORMAL: mController.scheduleTouchFeedback(); break; case RINGER_MODE_SILENT: effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); + hapticConstant = HapticFeedbackConstants.TOGGLE_OFF; break; case RINGER_MODE_VIBRATE: // Feedback handled by onStateChange, for feedback both when user toggles @@ -1332,8 +1340,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, break; default: effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); + hapticConstant = HapticFeedbackConstants.TOGGLE_ON; } - if (effect != null) { + if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { + mDialogView.performHapticFeedback(hapticConstant); + } else if (effect != null) { mController.vibrate(effect); } } @@ -1770,7 +1781,22 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, && mState.ringerModeInternal != -1 && mState.ringerModeInternal != state.ringerModeInternal && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { - mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK)); + + if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { + if (mShowing) { + // The dialog view is responsible for triggering haptics in the oneway API + mDialogView.performHapticFeedback(HapticFeedbackConstants.TOGGLE_ON); + } + /* + TODO(b/290642122): If the dialog is not showing, we have the case where haptics is + enabled by dragging the volume slider of Settings to a value of 0. This must be + handled by view Slices in Settings whilst using the performHapticFeedback API. + */ + + } else { + // Old behavior only active if the oneway API is not used. + mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK)); + } } mState = state; mDynamic.clear(); diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java index d0edc6e7ce4c..cc9f3e14216e 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -22,6 +22,7 @@ import android.os.Looper; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.VolumeDialog; @@ -61,7 +62,8 @@ public interface VolumeModule { InteractionJankMonitor interactionJankMonitor, CsdWarningDialog.Factory csdFactory, DevicePostureController devicePostureController, - DumpManager dumpManager) { + DumpManager dumpManager, + FeatureFlags featureFlags) { VolumeDialogImpl impl = new VolumeDialogImpl( context, volumeDialogController, @@ -76,7 +78,8 @@ public interface VolumeModule { csdFactory, devicePostureController, Looper.getMainLooper(), - dumpManager); + dumpManager, + featureFlags); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); impl.setSilentMode(false); 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 a64058968581..b45b8cd15bf5 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 @@ -16,9 +16,11 @@ package com.android.systemui.wallpapers.data.repository +import android.app.WallpaperInfo import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow /** @@ -29,5 +31,6 @@ import kotlinx.coroutines.flow.asStateFlow */ @SysUISingleton class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { + override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow() override val wallpaperSupportsAmbientMode = 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 48895ffcacb9..b8f95832b852 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 @@ -16,6 +16,7 @@ package com.android.systemui.wallpapers.data.repository +import android.app.WallpaperInfo import android.app.WallpaperManager import android.content.Context import android.content.Intent @@ -36,11 +37,15 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn /** A repository storing information about the current wallpaper. */ interface WallpaperRepository { + /** Emits the current user's current wallpaper. */ + val wallpaperInfo: StateFlow<WallpaperInfo?> + /** Emits true if the current user's current wallpaper supports ambient mode. */ val wallpaperSupportsAmbientMode: StateFlow<Boolean> } @@ -78,28 +83,35 @@ constructor( // Only update the wallpaper status once the user selection has finished. .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } - override val wallpaperSupportsAmbientMode: StateFlow<Boolean> = + override val wallpaperInfo: StateFlow<WallpaperInfo?> = if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) { - MutableStateFlow(false).asStateFlow() + MutableStateFlow(null).asStateFlow() } else { combine(wallpaperChanged, selectedUser) { _, selectedUser -> - doesWallpaperSupportAmbientMode(selectedUser) + getWallpaper(selectedUser) } .stateIn( scope, // Always be listening for wallpaper changes. SharingStarted.Eagerly, - initialValue = - doesWallpaperSupportAmbientMode(userRepository.selectedUser.value), + initialValue = getWallpaper(userRepository.selectedUser.value), ) } - private fun doesWallpaperSupportAmbientMode(selectedUser: SelectedUserModel): Boolean { - return wallpaperManager - .getWallpaperInfoForUser( - selectedUser.userInfo.id, + override val wallpaperSupportsAmbientMode: StateFlow<Boolean> = + wallpaperInfo + .map { + // If WallpaperInfo is null, it's ImageWallpaper which never supports ambient mode. + it?.supportsAmbientMode() == true + } + .stateIn( + scope, + // Always be listening for wallpaper changes. + SharingStarted.Eagerly, + initialValue = wallpaperInfo.value?.supportsAmbientMode() == true, ) - // If WallpaperInfo is null, it's ImageWallpaper which never supports ambient mode. - ?.supportsAmbientMode() == true + + private fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? { + return wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id) } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index 5d75428b8fb4..cb182297eae1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -76,7 +76,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController<BouncerKeyguardMessageArea> - @Mock private lateinit var mPostureController: DevicePostureController + @Mock private lateinit var mPostureController: DevicePostureController private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController private lateinit var fakeFeatureFlags: FakeFeatureFlags @@ -119,7 +119,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { mKeyguardPatternViewController.onViewAttached() - assertThat(getPatternTopGuideline()).isEqualTo(getExpectedTopGuideline()) + assertThat(getPatternTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio()) } @Test @@ -131,15 +131,20 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { mKeyguardPatternViewController.onViewAttached() // Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED - assertThat(getPatternTopGuideline()).isEqualTo(getExpectedTopGuideline()) + assertThat(getPatternTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio()) // Simulate posture change to state DEVICE_POSTURE_OPENED with callback verify(mPostureController).addCallback(postureCallbackCaptor.capture()) val postureCallback: DevicePostureController.Callback = postureCallbackCaptor.value postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED) - // Verify view is now in posture state DEVICE_POSTURE_OPENED - assertThat(getPatternTopGuideline()).isNotEqualTo(getExpectedTopGuideline()) + // Simulate posture change to same state with callback + assertThat(getPatternTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio()) + + postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED) + + // Verify view is still in posture state DEVICE_POSTURE_OPENED + assertThat(getPatternTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio()) } private fun getPatternTopGuideline(): Float { @@ -150,7 +155,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { return cs.getConstraint(R.id.pattern_top_guideline).layout.guidePercent } - private fun getExpectedTopGuideline(): Float { + private fun getHalfOpenedBouncerHeightRatio(): Float { return mContext.resources.getFloat(R.dimen.half_opened_bouncer_height_ratio) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index d256ee163877..4dc7652f83cf 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -19,6 +19,8 @@ package com.android.keyguard import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils @@ -32,6 +34,8 @@ import com.android.systemui.flags.Flags import com.android.systemui.statusbar.policy.DevicePostureController import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -51,7 +55,10 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class KeyguardPinViewControllerTest : SysuiTestCase() { - @Mock private lateinit var keyguardPinView: KeyguardPINView + + private lateinit var objectKeyguardPINView: KeyguardPINView + + @Mock private lateinit var mockKeyguardPinView: KeyguardPINView @Mock private lateinit var keyguardMessageArea: BouncerKeyguardMessageArea @@ -83,64 +90,73 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Mock lateinit var deleteButton: NumPadButton @Mock lateinit var enterButton: View - private lateinit var pinViewController: KeyguardPinViewController - @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback> @Before fun setup() { MockitoAnnotations.initMocks(this) - Mockito.`when`(keyguardPinView.requireViewById<View>(R.id.bouncer_message_area)) + Mockito.`when`(mockKeyguardPinView.requireViewById<View>(R.id.bouncer_message_area)) .thenReturn(keyguardMessageArea) Mockito.`when`( keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java)) ) .thenReturn(keyguardMessageAreaController) - `when`(keyguardPinView.passwordTextViewId).thenReturn(R.id.pinEntry) - `when`(keyguardPinView.findViewById<PasswordTextView>(R.id.pinEntry)) + `when`(mockKeyguardPinView.passwordTextViewId).thenReturn(R.id.pinEntry) + `when`(mockKeyguardPinView.findViewById<PasswordTextView>(R.id.pinEntry)) .thenReturn(passwordTextView) - `when`(keyguardPinView.resources).thenReturn(context.resources) - `when`(keyguardPinView.findViewById<NumPadButton>(R.id.delete_button)) + `when`(mockKeyguardPinView.resources).thenReturn(context.resources) + `when`(mockKeyguardPinView.findViewById<NumPadButton>(R.id.delete_button)) .thenReturn(deleteButton) - `when`(keyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton) + `when`(mockKeyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton) // For posture tests: - `when`(keyguardPinView.buttons).thenReturn(arrayOf()) + `when`(mockKeyguardPinView.buttons).thenReturn(arrayOf()) `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6) - pinViewController = - KeyguardPinViewController( - keyguardPinView, - keyguardUpdateMonitor, - securityMode, - lockPatternUtils, - mKeyguardSecurityCallback, - keyguardMessageAreaControllerFactory, - mLatencyTracker, - liftToActivateListener, - mEmergencyButtonController, - falsingCollector, - postureController, - featureFlags - ) + objectKeyguardPINView = + View.inflate(mContext, R.layout.keyguard_pin_view, null) + .findViewById(R.id.keyguard_pin_view) as KeyguardPINView + } + + private fun constructPinViewController( + mKeyguardPinView: KeyguardPINView + ): KeyguardPinViewController { + return KeyguardPinViewController( + mKeyguardPinView, + keyguardUpdateMonitor, + securityMode, + lockPatternUtils, + mKeyguardSecurityCallback, + keyguardMessageAreaControllerFactory, + mLatencyTracker, + liftToActivateListener, + mEmergencyButtonController, + falsingCollector, + postureController, + featureFlags + ) } @Test - fun onViewAttached_deviceHalfFolded_propagatedToPinView() { - `when`(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED) + fun onViewAttached_deviceHalfFolded_propagatedToPatternView() { + val pinViewController = constructPinViewController(objectKeyguardPINView) + overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f) + whenever(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED) pinViewController.onViewAttached() - verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED) + assertThat(getPinTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio()) } @Test - fun onDevicePostureChanged_deviceHalfFolded_propagatedToPinView() { - `when`(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED) + fun onDevicePostureChanged_deviceOpened_propagatedToPatternView() { + val pinViewController = constructPinViewController(objectKeyguardPINView) + overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f) - // Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED + whenever(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED) pinViewController.onViewAttached() - verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED) + // Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED + assertThat(getPinTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio()) // Simulate posture change to state DEVICE_POSTURE_OPENED with callback verify(postureController).addCallback(postureCallbackCaptor.capture()) @@ -148,31 +164,57 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED) // Verify view is now in posture state DEVICE_POSTURE_OPENED - verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_OPENED) + assertThat(getPinTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio()) + + // Simulate posture change to same state with callback + postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED) + + // Verify view is still in posture state DEVICE_POSTURE_OPENED + assertThat(getPinTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio()) + } + + private fun getPinTopGuideline(): Float { + val cs = ConstraintSet() + val container = objectKeyguardPINView.findViewById(R.id.pin_container) as ConstraintLayout + cs.clone(container) + return cs.getConstraint(R.id.pin_pad_top_guideline).layout.guidePercent + } + + private fun getHalfOpenedBouncerHeightRatio(): Float { + return mContext.resources.getFloat(R.dimen.half_opened_bouncer_height_ratio) } @Test fun startAppearAnimation() { + val pinViewController = constructPinViewController(mockKeyguardPinView) + pinViewController.startAppearAnimation() + verify(keyguardMessageAreaController) .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false) } @Test fun startAppearAnimation_withExistingMessage() { + val pinViewController = constructPinViewController(mockKeyguardPinView) Mockito.`when`(keyguardMessageAreaController.message).thenReturn("Unlock to continue.") + pinViewController.startAppearAnimation() + verify(keyguardMessageAreaController, Mockito.never()).setMessage(anyString(), anyBoolean()) } @Test fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsLessThan5() { + val pinViewController = constructPinViewController(mockKeyguardPinView) `when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true) + `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6) `when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true) `when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(3) `when`(passwordTextView.text).thenReturn("") pinViewController.startAppearAnimation() + verify(deleteButton).visibility = View.INVISIBLE verify(enterButton).visibility = View.INVISIBLE verify(passwordTextView).setUsePinShapes(true) @@ -181,12 +223,15 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Test fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsMoreThan5() { + val pinViewController = constructPinViewController(mockKeyguardPinView) `when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true) + `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6) `when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true) `when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(6) `when`(passwordTextView.text).thenReturn("") pinViewController.startAppearAnimation() + verify(deleteButton).visibility = View.VISIBLE verify(enterButton).visibility = View.VISIBLE verify(passwordTextView).setUsePinShapes(true) @@ -195,7 +240,10 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Test fun handleLockout_readsNumberOfErrorAttempts() { + val pinViewController = constructPinViewController(mockKeyguardPinView) + pinViewController.handleAttemptLockout(0) + verify(lockPatternUtils).getCurrentFailedPasswordAttempts(anyInt()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java index 6decb88ee148..5867a40c78fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java @@ -30,6 +30,8 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; @@ -43,12 +45,14 @@ import org.junit.runner.RunWith; @RunWithLooper public class ExpandHelperTest extends SysuiTestCase { + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); private ExpandableNotificationRow mRow; private ExpandHelper mExpandHelper; private ExpandHelper.Callback mCallback; @Before public void setUp() throws Exception { + mFeatureFlags.setDefault(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); mDependency.injectMockDependency(NotificationMediaManager.class); allowTestableLooperAsMainThread(); @@ -56,7 +60,8 @@ public class ExpandHelperTest extends SysuiTestCase { NotificationTestHelper helper = new NotificationTestHelper( mContext, mDependency, - TestableLooper.get(this)); + TestableLooper.get(this), + mFeatureFlags); mRow = helper.createRow(); mCallback = mock(ExpandHelper.Callback.class); mExpandHelper = new ExpandHelper(context, mCallback, 10, 100); diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt index da9ceb47446a..212dad78d5b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import android.widget.LinearLayout import android.widget.RelativeLayout import androidx.test.filters.SmallTest +import com.android.app.animation.Interpolators import com.android.systemui.SysuiTestCase import com.android.systemui.util.children import junit.framework.Assert.assertEquals @@ -19,7 +20,6 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import com.android.app.animation.Interpolators @SmallTest @RunWith(AndroidTestingRunner::class) @@ -178,7 +178,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test - fun animatesRootAndChildren() { + fun animatesRootAndChildren_withoutExcludedViews() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate(rootView) @@ -208,6 +208,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test + fun animatesRootAndChildren_withExcludedViews() { + setUpRootWithChildren() + + val success = ViewHierarchyAnimator.animate( + rootView, + excludedViews = setOf(rootView.getChildAt(0)) + ) + // Change all bounds. + rootView.measure( + View.MeasureSpec.makeMeasureSpec(180, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY) + ) + rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */) + + assertTrue(success) + assertNotNull(rootView.getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) + assertNotNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) + // The initial values for the affected views should be those of the previous layout, while + // the excluded view should be at the final values from the beginning. + checkBounds(rootView, l = 0, t = 0, r = 200, b = 100) + checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) + checkBounds(rootView.getChildAt(1), l = 100, t = 0, r = 200, b = 100) + endAnimation(rootView) + assertNull(rootView.getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) + assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) + // The end values should be those of the latest layout. + checkBounds(rootView, l = 10, t = 20, r = 200, b = 120) + checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) + checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) + } + + @Test fun animatesInvisibleViews() { rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */) rootView.visibility = View.INVISIBLE diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt index c223c5af6079..a6ad4b24b63d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt @@ -103,19 +103,6 @@ class AuthenticationInteractorTest : SysuiTestCase() { } @Test - fun toggleBypassEnabled() = - testScope.runTest { - val isBypassEnabled by collectLastValue(underTest.isBypassEnabled) - assertThat(isBypassEnabled).isFalse() - - underTest.toggleBypassEnabled() - assertThat(isBypassEnabled).isTrue() - - underTest.toggleBypassEnabled() - assertThat(isBypassEnabled).isFalse() - } - - @Test fun isAuthenticationRequired_lockedAndSecured_true() = testScope.runTest { utils.authenticationRepository.setUnlocked(false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt index eaa31ac1d157..ecc776b98c6c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt @@ -48,6 +48,7 @@ import android.view.WindowMetrics import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase @@ -64,7 +65,6 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.FakeExecutor @@ -153,8 +153,8 @@ class SideFpsControllerTest : SysuiTestCase() { mock(KeyguardStateController::class.java), keyguardBouncerRepository, FakeBiometricSettingsRepository(), - FakeDeviceEntryFingerprintAuthRepository(), FakeSystemClock(), + mock(KeyguardUpdateMonitor::class.java), ) displayStateInteractor = DisplayStateInteractorImpl( diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt index 9df06dc9e18f..8dfeb3bde0c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt @@ -34,7 +34,6 @@ import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.FakeTrustRepository import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -106,8 +105,8 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest : mock(KeyguardStateController::class.java), keyguardBouncerRepository, mock(BiometricSettingsRepository::class.java), - mock(DeviceEntryFingerprintAuthRepository::class.java), mock(SystemClock::class.java), + mKeyguardUpdateMonitor, ) return createUdfpsKeyguardViewController( /* useModernBouncer */ true, /* useExpandedOverlay */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt index 37b9ca49ef57..186df02536ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.bouncer.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository @@ -54,6 +55,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var systemClock: SystemClock @Mock private lateinit var bouncerLogger: TableLogBuffer + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Before fun setup() { @@ -72,8 +74,8 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { keyguardStateController, bouncerRepository, biometricSettingsRepository, - deviceEntryFingerprintAuthRepository, systemClock, + keyguardUpdateMonitor, ) } @@ -118,7 +120,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { @Test fun canShowAlternateBouncerForFingerprint_fingerprintLockedOut() { givenCanShowAlternateBouncer() - deviceEntryFingerprintAuthRepository.setLockedOut(true) + whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true) assertFalse(underTest.canShowAlternateBouncerForFingerprint()) } @@ -168,7 +170,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { biometricSettingsRepository.setFingerprintEnrolled(true) biometricSettingsRepository.setStrongBiometricAllowed(true) biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true) - deviceEntryFingerprintAuthRepository.setLockedOut(false) + whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false) whenever(keyguardStateController.isUnlocked).thenReturn(false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java index 461ec653d819..40f0ed3626db 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java @@ -28,10 +28,10 @@ import androidx.lifecycle.Observer; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dreams.DreamLogger; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.log.core.FakeLogBuffer; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -57,8 +57,6 @@ public class ComplicationCollectionLiveDataTest extends SysuiTestCase { private FakeFeatureFlags mFeatureFlags; @Mock private Observer mObserver; - @Mock - private DreamLogger mLogger; @Before public void setUp() { @@ -70,7 +68,7 @@ public class ComplicationCollectionLiveDataTest extends SysuiTestCase { mExecutor, /* overlayEnabled= */ true, mFeatureFlags, - mLogger); + FakeLogBuffer.Factory.Companion.create()); mLiveData = new ComplicationCollectionLiveData(mStateController); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index a00e5456b711..57307fc84b1c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -9,6 +9,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.complication.ComplicationHostViewController import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel +import com.android.systemui.log.core.FakeLogBuffer import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.mockito.argumentCaptor @@ -47,7 +48,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { @Mock private lateinit var stateController: DreamOverlayStateController @Mock private lateinit var configController: ConfigurationController @Mock private lateinit var transitionViewModel: DreamingToLockscreenTransitionViewModel - @Mock private lateinit var logger: DreamLogger + private val logBuffer = FakeLogBuffer.Factory.create() private lateinit var controller: DreamOverlayAnimationsController @Before @@ -66,7 +67,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { DREAM_IN_COMPLICATIONS_ANIMATION_DURATION, DREAM_IN_TRANSLATION_Y_DISTANCE, DREAM_IN_TRANSLATION_Y_DURATION, - logger + logBuffer ) val mockView: View = mock() diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java index 2c1ebe4121af..44a78ac3bc96 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java @@ -34,6 +34,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.complication.Complication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.core.FakeLogBuffer; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -58,8 +60,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; - @Mock - private DreamLogger mLogger; + private final LogBuffer mLogBuffer = FakeLogBuffer.Factory.Companion.create(); final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); @@ -408,6 +409,11 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase { } private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) { - return new DreamOverlayStateController(mExecutor, overlayEnabled, mFeatureFlags, mLogger); + return new DreamOverlayStateController( + mExecutor, + overlayEnabled, + mFeatureFlags, + mLogBuffer + ); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java index 5dc0e55632fd..4e74f451932b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java @@ -48,6 +48,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.core.FakeLogBuffer; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; import com.android.systemui.statusbar.policy.NextAlarmController; @@ -113,8 +115,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { DreamOverlayStateController mDreamOverlayStateController; @Mock UserTracker mUserTracker; - @Mock - DreamLogger mLogger; + + LogBuffer mLogBuffer = FakeLogBuffer.Factory.Companion.create(); @Captor private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor; @@ -149,7 +151,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { mDreamOverlayStatusBarItemsProvider, mDreamOverlayStateController, mUserTracker, - mLogger); + mLogBuffer); } @Test @@ -293,7 +295,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { mDreamOverlayStatusBarItemsProvider, mDreamOverlayStateController, mUserTracker, - mLogger); + mLogBuffer); controller.onViewAttached(); verify(mView, never()).showIcon( eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 666978e78f98..7379cd51d383 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -71,6 +71,7 @@ import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.TestScopeProvider; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; @@ -108,9 +109,11 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SystemSettings; import com.android.systemui.util.time.FakeSystemClock; +import com.android.systemui.wallpapers.data.repository.FakeWallpaperRepository; import com.android.wm.shell.keyguard.KeyguardTransitions; import org.junit.After; @@ -124,6 +127,7 @@ import org.mockito.MockitoAnnotations; import kotlinx.coroutines.CoroutineDispatcher; import kotlinx.coroutines.flow.Flow; +import kotlinx.coroutines.test.TestScope; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -131,6 +135,9 @@ import kotlinx.coroutines.flow.Flow; public class KeyguardViewMediatorTest extends SysuiTestCase { private KeyguardViewMediator mViewMediator; + private final TestScope mTestScope = TestScopeProvider.getTestScope(); + private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope()); + private @Mock UserTracker mUserTracker; private @Mock DevicePolicyManager mDevicePolicyManager; private @Mock LockPatternUtils mLockPatternUtils; @@ -182,6 +189,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock SecureSettings mSecureSettings; private @Mock AlarmManager mAlarmManager; private FakeSystemClock mSystemClock; + private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository(); private @Mock CoroutineDispatcher mDispatcher; private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel; @@ -817,6 +825,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mKeyguardTransitions, mInteractionJankMonitor, mDreamOverlayStateController, + mJavaAdapter, + mWallpaperRepository, () -> mShadeController, () -> mNotificationShadeWindowController, () -> mActivityLaunchAnimator, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt index f9070b37ca48..c6a2fa50b446 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt @@ -162,11 +162,11 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { @Test fun convenienceBiometricAllowedChange() = testScope.runTest { + overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false) createBiometricSettingsRepository() val convenienceBiometricAllowed = collectLastValue(underTest.isNonStrongBiometricAllowed) runCurrent() - onNonStrongAuthChanged(true, PRIMARY_USER_ID) assertThat(convenienceBiometricAllowed()).isTrue() @@ -175,6 +175,45 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { onNonStrongAuthChanged(false, PRIMARY_USER_ID) assertThat(convenienceBiometricAllowed()).isFalse() + mContext.orCreateTestableResources.removeOverride( + com.android.internal.R.bool.config_strongAuthRequiredOnBoot + ) + } + + @Test + fun whenStrongAuthRequiredAfterBoot_nonStrongBiometricNotAllowed() = + testScope.runTest { + overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, true) + createBiometricSettingsRepository() + + val convenienceBiometricAllowed = + collectLastValue(underTest.isNonStrongBiometricAllowed) + runCurrent() + onNonStrongAuthChanged(true, PRIMARY_USER_ID) + + assertThat(convenienceBiometricAllowed()).isFalse() + mContext.orCreateTestableResources.removeOverride( + com.android.internal.R.bool.config_strongAuthRequiredOnBoot + ) + } + + @Test + fun whenStrongBiometricAuthIsNotAllowed_nonStrongBiometrics_alsoNotAllowed() = + testScope.runTest { + overrideResource(com.android.internal.R.bool.config_strongAuthRequiredOnBoot, false) + createBiometricSettingsRepository() + + val convenienceBiometricAllowed = + collectLastValue(underTest.isNonStrongBiometricAllowed) + runCurrent() + onNonStrongAuthChanged(true, PRIMARY_USER_ID) + assertThat(convenienceBiometricAllowed()).isTrue() + + onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, PRIMARY_USER_ID) + assertThat(convenienceBiometricAllowed()).isFalse() + mContext.orCreateTestableResources.removeOverride( + com.android.internal.R.bool.config_strongAuthRequiredOnBoot + ) } private fun onStrongAuthChanged(flags: Int, userId: Int) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index 020c0b22ba27..47c662c3b4b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -36,6 +36,7 @@ import com.android.internal.logging.UiEventLogger import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase @@ -50,12 +51,12 @@ import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.DetectionStatus -import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus -import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus +import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.KeyguardState -import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus +import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.shared.model.WakeSleepReason @@ -113,6 +114,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { @Mock private lateinit var sessionTracker: SessionTracker @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var dumpManager: DumpManager + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Captor private lateinit var authenticationCallback: ArgumentCaptor<FaceManager.AuthenticationCallback> @@ -131,8 +133,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository private lateinit var testScope: TestScope private lateinit var fakeUserRepository: FakeUserRepository - private lateinit var authStatus: FlowValue<AuthenticationStatus?> - private lateinit var detectStatus: FlowValue<DetectionStatus?> + private lateinit var authStatus: FlowValue<FaceAuthenticationStatus?> + private lateinit var detectStatus: FlowValue<FaceDetectionStatus?> private lateinit var authRunning: FlowValue<Boolean?> private lateinit var bypassEnabled: FlowValue<Boolean?> private lateinit var lockedOut: FlowValue<Boolean?> @@ -175,10 +177,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { AlternateBouncerInteractor( bouncerRepository = bouncerRepository, biometricSettingsRepository = biometricSettingsRepository, - deviceEntryFingerprintAuthRepository = deviceEntryFingerprintAuthRepository, systemClock = mock(SystemClock::class.java), keyguardStateController = FakeKeyguardStateController(), statusBarStateController = mock(StatusBarStateController::class.java), + keyguardUpdateMonitor = keyguardUpdateMonitor, ) bypassStateChangedListener = @@ -262,7 +264,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { val successResult = successResult() authenticationCallback.value.onAuthenticationSucceeded(successResult) - assertThat(authStatus()).isEqualTo(SuccessAuthenticationStatus(successResult)) + assertThat(authStatus()).isEqualTo(SuccessFaceAuthenticationStatus(successResult)) assertThat(authenticated()).isTrue() assertThat(authRunning()).isFalse() assertThat(canFaceAuthRun()).isFalse() @@ -383,7 +385,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { detectionCallback.value.onFaceDetected(1, 1, true) - assertThat(detectStatus()).isEqualTo(DetectionStatus(1, 1, true)) + assertThat(detectStatus()).isEqualTo(FaceDetectionStatus(1, 1, true)) } @Test @@ -423,7 +425,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { FACE_ERROR_CANCELED, "First auth attempt cancellation completed" ) - val value = authStatus() as ErrorAuthenticationStatus + val value = authStatus() as ErrorFaceAuthenticationStatus assertThat(value.msgId).isEqualTo(FACE_ERROR_CANCELED) assertThat(value.msg).isEqualTo("First auth attempt cancellation completed") @@ -465,7 +467,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { authenticationCallback.value.onAuthenticationHelp(10, "Ignored help msg") authenticationCallback.value.onAuthenticationHelp(11, "Ignored help msg") - assertThat(authStatus()).isEqualTo(HelpAuthenticationStatus(9, "help msg")) + assertThat(authStatus()).isEqualTo(HelpFaceAuthenticationStatus(9, "help msg")) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt index 264328b04227..def016ad8381 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt @@ -26,7 +26,11 @@ import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthController import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.dump.DumpManager +import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -49,7 +53,6 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor - @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var authController: AuthController @Captor private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> @@ -68,7 +71,6 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { authController, keyguardUpdateMonitor, testScope.backgroundScope, - dumpManager, ) } @@ -177,4 +179,129 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { callback.value.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT) assertThat(availableFpSensorType()).isEqualTo(BiometricType.UNDER_DISPLAY_FINGERPRINT) } + + @Test + fun onFingerprintSuccess_successAuthenticationStatus() = + testScope.runTest { + val authenticationStatus by collectLastValue(underTest.authenticationStatus) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricAuthenticated( + 0, + BiometricSourceType.FINGERPRINT, + true, + ) + + val status = authenticationStatus as SuccessFingerprintAuthenticationStatus + assertThat(status.userId).isEqualTo(0) + assertThat(status.isStrongBiometric).isEqualTo(true) + } + + @Test + fun onFingerprintFailed_failedAuthenticationStatus() = + testScope.runTest { + val authenticationStatus by collectLastValue(underTest.authenticationStatus) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricAuthFailed( + BiometricSourceType.FINGERPRINT, + ) + + assertThat(authenticationStatus) + .isInstanceOf(FailFingerprintAuthenticationStatus::class.java) + } + + @Test + fun onFingerprintError_errorAuthenticationStatus() = + testScope.runTest { + val authenticationStatus by collectLastValue(underTest.authenticationStatus) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricError( + 1, + "test_string", + BiometricSourceType.FINGERPRINT, + ) + + val status = authenticationStatus as ErrorFingerprintAuthenticationStatus + assertThat(status.msgId).isEqualTo(1) + assertThat(status.msg).isEqualTo("test_string") + } + + @Test + fun onFingerprintHelp_helpAuthenticationStatus() = + testScope.runTest { + val authenticationStatus by collectLastValue(underTest.authenticationStatus) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricHelp( + 1, + "test_string", + BiometricSourceType.FINGERPRINT, + ) + + val status = authenticationStatus as HelpFingerprintAuthenticationStatus + assertThat(status.msgId).isEqualTo(1) + assertThat(status.msg).isEqualTo("test_string") + } + + @Test + fun onFingerprintAcquired_acquiredAuthenticationStatus() = + testScope.runTest { + val authenticationStatus by collectLastValue(underTest.authenticationStatus) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricAcquired( + BiometricSourceType.FINGERPRINT, + 5, + ) + + val status = authenticationStatus as AcquiredFingerprintAuthenticationStatus + assertThat(status.acquiredInfo).isEqualTo(5) + } + + @Test + fun onFaceCallbacks_fingerprintAuthenticationStatusIsUnchanged() = + testScope.runTest { + val authenticationStatus by collectLastValue(underTest.authenticationStatus) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricAuthenticated( + 0, + BiometricSourceType.FACE, + true, + ) + assertThat(authenticationStatus).isNull() + + updateMonitorCallback.value.onBiometricAuthFailed( + BiometricSourceType.FACE, + ) + assertThat(authenticationStatus).isNull() + + updateMonitorCallback.value.onBiometricHelp( + 1, + "test_string", + BiometricSourceType.FACE, + ) + assertThat(authenticationStatus).isNull() + + updateMonitorCallback.value.onBiometricAcquired( + BiometricSourceType.FACE, + 5, + ) + assertThat(authenticationStatus).isNull() + + updateMonitorCallback.value.onBiometricError( + 1, + "test_string", + BiometricSourceType.FACE, + ) + assertThat(authenticationStatus).isNull() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index e9f0d561371c..ba7d3490e56d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -31,16 +31,20 @@ import com.android.systemui.doze.DozeMachine import com.android.systemui.doze.DozeTransitionCallback import com.android.systemui.doze.DozeTransitionListener import com.android.systemui.dreams.DreamOverlayCallbackController +import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.shared.model.ScreenModel +import com.android.systemui.keyguard.shared.model.ScreenState import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.whenever @@ -70,9 +74,11 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle + @Mock private lateinit var screenLifecycle: ScreenLifecycle @Mock private lateinit var biometricUnlockController: BiometricUnlockController @Mock private lateinit var dozeTransitionListener: DozeTransitionListener @Mock private lateinit var authController: AuthController + @Mock private lateinit var keyguardBypassController: KeyguardBypassController @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController @Mock private lateinit var dozeParameters: DozeParameters @@ -90,8 +96,10 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { KeyguardRepositoryImpl( statusBarStateController, wakefulnessLifecycle, + screenLifecycle, biometricUnlockController, keyguardStateController, + keyguardBypassController, keyguardUpdateMonitor, dozeTransitionListener, dozeParameters, @@ -157,6 +165,16 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun dozeTimeTick() = + testScope.runTest { + var dozeTimeTickValue = collectLastValue(underTest.dozeTimeTick) + underTest.dozeTimeTick() + runCurrent() + + assertThat(dozeTimeTickValue()).isNull() + } + + @Test fun isKeyguardShowing() = testScope.runTest { whenever(keyguardStateController.isShowing).thenReturn(false) @@ -186,6 +204,20 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun isBypassEnabled_disabledInController() { + whenever(keyguardBypassController.isBypassEnabled).thenReturn(false) + whenever(keyguardBypassController.bypassEnabled).thenReturn(false) + assertThat(underTest.isBypassEnabled()).isFalse() + } + + @Test + fun isBypassEnabled_enabledInController() { + whenever(keyguardBypassController.isBypassEnabled).thenReturn(true) + whenever(keyguardBypassController.bypassEnabled).thenReturn(true) + assertThat(underTest.isBypassEnabled()).isTrue() + } + + @Test fun isAodAvailable() = runTest { val flow = underTest.isAodAvailable var isAodAvailable = collectLastValue(flow) @@ -354,6 +386,48 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun screenModel() = + testScope.runTest { + val values = mutableListOf<ScreenModel>() + val job = underTest.screenModel.onEach(values::add).launchIn(this) + + runCurrent() + val captor = argumentCaptor<ScreenLifecycle.Observer>() + verify(screenLifecycle).addObserver(captor.capture()) + + whenever(screenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_TURNING_ON) + captor.value.onScreenTurningOn() + runCurrent() + + whenever(screenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_ON) + captor.value.onScreenTurnedOn() + runCurrent() + + whenever(screenLifecycle.getScreenState()) + .thenReturn(ScreenLifecycle.SCREEN_TURNING_OFF) + captor.value.onScreenTurningOff() + runCurrent() + + whenever(screenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_OFF) + captor.value.onScreenTurnedOff() + runCurrent() + + assertThat(values.map { it.state }) + .isEqualTo( + listOf( + // Initial value will be OFF + ScreenState.SCREEN_OFF, + ScreenState.SCREEN_TURNING_ON, + ScreenState.SCREEN_ON, + ScreenState.SCREEN_TURNING_OFF, + ScreenState.SCREEN_OFF, + ) + ) + + job.cancel() + } + + @Test fun isUdfpsSupported() = testScope.runTest { whenever(keyguardUpdateMonitor.isUdfpsSupported).thenReturn(true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BiometricMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BiometricMessageInteractorTest.kt new file mode 100644 index 000000000000..3389fa9a48af --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BiometricMessageInteractorTest.kt @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.domain.interactor + +import android.hardware.biometrics.BiometricSourceType.FINGERPRINT +import android.hardware.fingerprint.FingerprintManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus +import com.android.systemui.keyguard.util.IndicationHelper +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class BiometricMessageInteractorTest : SysuiTestCase() { + + private lateinit var underTest: BiometricMessageInteractor + private lateinit var testScope: TestScope + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository + private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository + + @Mock private lateinit var indicationHelper: IndicationHelper + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + testScope = TestScope() + fingerprintPropertyRepository = FakeFingerprintPropertyRepository() + fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() + underTest = + BiometricMessageInteractor( + mContext.resources, + fingerprintAuthRepository, + fingerprintPropertyRepository, + indicationHelper, + keyguardUpdateMonitor, + ) + } + + @Test + fun fingerprintErrorMessage() = + testScope.runTest { + val fingerprintErrorMessage by collectLastValue(underTest.fingerprintErrorMessage) + + // GIVEN FINGERPRINT_ERROR_HW_UNAVAILABLE should NOT be suppressed + whenever( + indicationHelper.shouldSuppressErrorMsg( + FINGERPRINT, + FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE + ) + ) + .thenReturn(false) + + // WHEN authentication status error is FINGERPRINT_ERROR_HW_UNAVAILABLE + fingerprintAuthRepository.setAuthenticationStatus( + ErrorFingerprintAuthenticationStatus( + msgId = FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, + msg = "test" + ) + ) + + // THEN fingerprintErrorMessage is updated + assertThat(fingerprintErrorMessage?.source).isEqualTo(FINGERPRINT) + assertThat(fingerprintErrorMessage?.type).isEqualTo(BiometricMessageType.ERROR) + assertThat(fingerprintErrorMessage?.id) + .isEqualTo(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) + assertThat(fingerprintErrorMessage?.message).isEqualTo("test") + } + + @Test + fun fingerprintErrorMessage_suppressedError() = + testScope.runTest { + val fingerprintErrorMessage by collectLastValue(underTest.fingerprintErrorMessage) + + // GIVEN FINGERPRINT_ERROR_HW_UNAVAILABLE should be suppressed + whenever( + indicationHelper.shouldSuppressErrorMsg( + FINGERPRINT, + FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE + ) + ) + .thenReturn(true) + + // WHEN authentication status error is FINGERPRINT_ERROR_HW_UNAVAILABLE + fingerprintAuthRepository.setAuthenticationStatus( + ErrorFingerprintAuthenticationStatus( + msgId = FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, + msg = "test" + ) + ) + + // THEN fingerprintErrorMessage isn't update - it's still null + assertThat(fingerprintErrorMessage).isNull() + } + + @Test + fun fingerprintHelpMessage() = + testScope.runTest { + val fingerprintHelpMessage by collectLastValue(underTest.fingerprintHelpMessage) + + // GIVEN primary auth is NOT required + whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())) + .thenReturn(true) + + // WHEN authentication status help is FINGERPRINT_ACQUIRED_IMAGER_DIRTY + fingerprintAuthRepository.setAuthenticationStatus( + HelpFingerprintAuthenticationStatus( + msgId = FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY, + msg = "test" + ) + ) + + // THEN fingerprintHelpMessage is updated + assertThat(fingerprintHelpMessage?.source).isEqualTo(FINGERPRINT) + assertThat(fingerprintHelpMessage?.type).isEqualTo(BiometricMessageType.HELP) + assertThat(fingerprintHelpMessage?.id) + .isEqualTo(FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY) + assertThat(fingerprintHelpMessage?.message).isEqualTo("test") + } + + @Test + fun fingerprintHelpMessage_primaryAuthRequired() = + testScope.runTest { + val fingerprintHelpMessage by collectLastValue(underTest.fingerprintHelpMessage) + + // GIVEN primary auth is required + whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())) + .thenReturn(false) + + // WHEN authentication status help is FINGERPRINT_ACQUIRED_IMAGER_DIRTY + fingerprintAuthRepository.setAuthenticationStatus( + HelpFingerprintAuthenticationStatus( + msgId = FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY, + msg = "test" + ) + ) + + // THEN fingerprintHelpMessage isn't update - it's still null + assertThat(fingerprintHelpMessage).isNull() + } + + @Test + fun fingerprintFailMessage_nonUdfps() = + testScope.runTest { + val fingerprintFailMessage by collectLastValue(underTest.fingerprintFailMessage) + + // GIVEN primary auth is NOT required + whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())) + .thenReturn(true) + + // GIVEN rear fingerprint (not UDFPS) + fingerprintPropertyRepository.setProperties( + 0, + SensorStrength.STRONG, + FingerprintSensorType.REAR, + mapOf() + ) + + // WHEN authentication status fail + fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus) + + // THEN fingerprintFailMessage is updated + assertThat(fingerprintFailMessage?.source).isEqualTo(FINGERPRINT) + assertThat(fingerprintFailMessage?.type).isEqualTo(BiometricMessageType.FAIL) + assertThat(fingerprintFailMessage?.id) + .isEqualTo(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED) + assertThat(fingerprintFailMessage?.message) + .isEqualTo( + mContext.resources.getString( + com.android.internal.R.string.fingerprint_error_not_match + ) + ) + } + + @Test + fun fingerprintFailMessage_udfps() = + testScope.runTest { + val fingerprintFailMessage by collectLastValue(underTest.fingerprintFailMessage) + + // GIVEN primary auth is NOT required + whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())) + .thenReturn(true) + + // GIVEN UDFPS + fingerprintPropertyRepository.setProperties( + 0, + SensorStrength.STRONG, + FingerprintSensorType.UDFPS_OPTICAL, + mapOf() + ) + + // WHEN authentication status fail + fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus) + + // THEN fingerprintFailMessage is updated to udfps message + assertThat(fingerprintFailMessage?.source).isEqualTo(FINGERPRINT) + assertThat(fingerprintFailMessage?.type).isEqualTo(BiometricMessageType.FAIL) + assertThat(fingerprintFailMessage?.id) + .isEqualTo(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED) + assertThat(fingerprintFailMessage?.message) + .isEqualTo( + mContext.resources.getString( + com.android.internal.R.string.fingerprint_udfps_error_not_match + ) + ) + } + + @Test + fun fingerprintFailedMessage_primaryAuthRequired() = + testScope.runTest { + val fingerprintFailedMessage by collectLastValue(underTest.fingerprintFailMessage) + + // GIVEN primary auth is required + whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())) + .thenReturn(false) + + // WHEN authentication status fail + fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus) + + // THEN fingerprintFailedMessage isn't update - it's still null + assertThat(fingerprintFailedMessage).isNull() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index 3e81cd336824..ced0a213ca97 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -38,10 +38,9 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.FakeTrustRepository -import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep @@ -121,8 +120,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { mock(KeyguardStateController::class.java), bouncerRepository, mock(BiometricSettingsRepository::class.java), - FakeDeviceEntryFingerprintAuthRepository(), FakeSystemClock(), + keyguardUpdateMonitor, ), keyguardTransitionInteractor, featureFlags, @@ -160,7 +159,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { underTest.onDeviceLifted() - val outputValue = authenticationStatus()!! as ErrorAuthenticationStatus + val outputValue = authenticationStatus()!! as ErrorFaceAuthenticationStatus assertThat(outputValue.msgId) .isEqualTo(BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT) assertThat(outputValue.msg).isEqualTo("Face Unlock unavailable") diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/core/FakeLogBuffer.kt b/packages/SystemUI/tests/src/com/android/systemui/log/core/FakeLogBuffer.kt new file mode 100644 index 000000000000..272d686e974b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/log/core/FakeLogBuffer.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.log.core + +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogMessageImpl +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.nullable +import com.android.systemui.util.mockito.whenever +import org.mockito.Mockito.anyString + +/** + * A fake [LogBuffer] used for testing that obtains a real [LogMessage] to prevent a + * [NullPointerException]. + */ +class FakeLogBuffer private constructor() { + class Factory private constructor() { + companion object { + fun create(): LogBuffer { + val logBuffer = mock<LogBuffer>() + whenever( + logBuffer.obtain( + tag = anyString(), + level = any(), + messagePrinter = any(), + exception = nullable(), + ) + ) + .thenReturn(LogMessageImpl.Factory.create()) + return logBuffer + } + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt index b4b307301138..9a90a5ceb259 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt @@ -216,9 +216,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var recCardTitle: TextView @Mock private lateinit var coverItem: ImageView @Mock private lateinit var matrix: Matrix - private lateinit var coverItem1: ImageView - private lateinit var coverItem2: ImageView - private lateinit var coverItem3: ImageView private lateinit var recTitle1: TextView private lateinit var recTitle2: TextView private lateinit var recTitle3: TextView @@ -233,7 +230,6 @@ public class MediaControlPanelTest : SysuiTestCase() { FakeFeatureFlags().apply { this.set(Flags.UMO_SURFACE_RIPPLE, false) this.set(Flags.UMO_TURBULENCE_NOISE, false) - this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false) } @Mock private lateinit var globalSettings: GlobalSettings @@ -467,21 +463,25 @@ public class MediaControlPanelTest : SysuiTestCase() { recSubtitle3 = TextView(context) whenever(recommendationViewHolder.recommendations).thenReturn(view) - whenever(recommendationViewHolder.cardIcon).thenReturn(appIcon) - - // Add a recommendation item - coverItem1 = ImageView(context).also { it.setId(R.id.media_cover1) } - coverItem2 = ImageView(context).also { it.setId(R.id.media_cover2) } - coverItem3 = ImageView(context).also { it.setId(R.id.media_cover3) } - + whenever(recommendationViewHolder.mediaAppIcons) + .thenReturn(listOf(recAppIconItem, recAppIconItem, recAppIconItem)) + whenever(recommendationViewHolder.cardTitle).thenReturn(recCardTitle) whenever(recommendationViewHolder.mediaCoverItems) - .thenReturn(listOf(coverItem1, coverItem2, coverItem3)) + .thenReturn(listOf(coverItem, coverItem, coverItem)) whenever(recommendationViewHolder.mediaCoverContainers) .thenReturn(listOf(coverContainer1, coverContainer2, coverContainer3)) whenever(recommendationViewHolder.mediaTitles) .thenReturn(listOf(recTitle1, recTitle2, recTitle3)) whenever(recommendationViewHolder.mediaSubtitles) .thenReturn(listOf(recSubtitle1, recSubtitle2, recSubtitle3)) + whenever(recommendationViewHolder.mediaProgressBars) + .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3)) + whenever(coverItem.imageMatrix).thenReturn(matrix) + + // set ids for recommendation containers + whenever(coverContainer1.id).thenReturn(1) + whenever(coverContainer2.id).thenReturn(2) + whenever(coverContainer3.id).thenReturn(3) whenever(recommendationViewHolder.gutsViewHolder).thenReturn(gutsViewHolder) @@ -1561,7 +1561,8 @@ public class MediaControlPanelTest : SysuiTestCase() { verify(viewHolder.player).contentDescription = descriptionCaptor.capture() val description = descriptionCaptor.value.toString() - assertThat(description).contains(REC_APP_NAME) + assertThat(description) + .isEqualTo(context.getString(R.string.controls_media_smartspace_rec_header)) } @Test @@ -1585,7 +1586,8 @@ public class MediaControlPanelTest : SysuiTestCase() { verify(viewHolder.player).contentDescription = descriptionCaptor.capture() val description = descriptionCaptor.value.toString() - assertThat(description).contains(REC_APP_NAME) + assertThat(description) + .isEqualTo(context.getString(R.string.controls_media_smartspace_rec_header)) } @Test @@ -2151,7 +2153,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindRecommendation_setAfterExecutors() { - setupUpdatedRecommendationViewHolder() val albumArt = getColorIcon(Color.RED) val data = smartspaceData.copy( @@ -2189,7 +2190,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindRecommendationWithProgressBars() { useRealConstraintSets() - setupUpdatedRecommendationViewHolder() val albumArt = getColorIcon(Color.RED) val bundle = Bundle().apply { @@ -2236,7 +2236,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindRecommendation_carouselNotFitThreeRecs_OrientationPortrait() { useRealConstraintSets() - setupUpdatedRecommendationViewHolder() val albumArt = getColorIcon(Color.RED) val data = smartspaceData.copy( @@ -2290,7 +2289,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindRecommendation_carouselNotFitThreeRecs_OrientationLandscape() { useRealConstraintSets() - setupUpdatedRecommendationViewHolder() val albumArt = getColorIcon(Color.RED) val data = smartspaceData.copy( @@ -2505,27 +2503,6 @@ public class MediaControlPanelTest : SysuiTestCase() { verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent)) } - private fun setupUpdatedRecommendationViewHolder() { - fakeFeatureFlag.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, true) - whenever(recommendationViewHolder.mediaAppIcons) - .thenReturn(listOf(recAppIconItem, recAppIconItem, recAppIconItem)) - whenever(recommendationViewHolder.cardTitle).thenReturn(recCardTitle) - whenever(recommendationViewHolder.mediaCoverContainers) - .thenReturn(listOf(coverContainer1, coverContainer2, coverContainer3)) - whenever(recommendationViewHolder.mediaCoverItems) - .thenReturn(listOf(coverItem, coverItem, coverItem)) - whenever(recommendationViewHolder.mediaProgressBars) - .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3)) - whenever(recommendationViewHolder.mediaSubtitles) - .thenReturn(listOf(recSubtitle1, recSubtitle2, recSubtitle3)) - whenever(coverItem.imageMatrix).thenReturn(matrix) - - // set ids for recommendation containers - whenever(coverContainer1.id).thenReturn(1) - whenever(coverContainer2.id).thenReturn(2) - whenever(coverContainer3.id).thenReturn(3) - } - private fun getColorIcon(color: Int): Icon { val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) val canvas = Canvas(bmp) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt index c9956f36dbeb..ba97df910e43 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt @@ -201,8 +201,8 @@ class MediaViewControllerTest : SysuiTestCase() { whenever(mockCopiedState.widgetStates) .thenReturn( mutableMapOf( - R.id.media_title1 to mediaTitleWidgetState, - R.id.media_subtitle1 to mediaSubTitleWidgetState, + R.id.media_title to mediaTitleWidgetState, + R.id.media_subtitle to mediaSubTitleWidgetState, R.id.media_cover1_container to mediaContainerWidgetState ) ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt index 45bb9313264c..435a1f1327d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt @@ -182,6 +182,32 @@ class PowerInteractorTest : SysuiTestCase() { assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION) } + @Test + fun wakeUpIfDreaming_dreaming_woken() { + // GIVEN device is dreaming + whenever(statusBarStateController.isDreaming).thenReturn(true) + + // WHEN wakeUpIfDreaming is called + underTest.wakeUpIfDreaming("testReason", PowerManager.WAKE_REASON_GESTURE) + + // THEN device is woken up + assertThat(repository.lastWakeWhy).isEqualTo("testReason") + assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE) + } + + @Test + fun wakeUpIfDreaming_notDreaming_notWoken() { + // GIVEN device is not dreaming + whenever(statusBarStateController.isDreaming).thenReturn(false) + + // WHEN wakeUpIfDreaming is called + underTest.wakeUpIfDreaming("why", PowerManager.WAKE_REASON_TAP) + + // THEN device is not woken + assertThat(repository.lastWakeWhy).isNull() + assertThat(repository.lastWakeReason).isNull() + } + companion object { private val IMMEDIATE = Dispatchers.Main.immediate } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt index a0d8f98a4ad1..9d9d0c7de2ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt @@ -154,6 +154,21 @@ class QSPanelControllerTest : SysuiTestCase() { verify(qsPanel).setCanCollapse(true) } + @Test + fun multipleListeningOnlyCallsBrightnessControllerOnce() { + controller.setListening(true, true) + controller.setListening(true, false) + controller.setListening(true, true) + + verify(brightnessController).registerCallbacks() + + controller.setListening(false, true) + controller.setListening(false, false) + controller.setListening(false, true) + + verify(brightnessController).unregisterCallbacks() + } + private fun setShouldUseSplitShade(shouldUse: Boolean) { testableResources.addOverride(R.bool.config_use_split_notification_shade, shouldUse) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt index 3e9ddcb06389..5638d708cf30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt @@ -28,7 +28,6 @@ import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.runTest import org.junit.Before @@ -36,7 +35,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @@ -385,7 +383,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { ) { featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled) authenticationRepository.setUnlocked(isDeviceUnlocked) - authenticationRepository.setBypassEnabled(isBypassEnabled) + keyguardRepository.setBypassEnabled(isBypassEnabled) initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(it)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt new file mode 100644 index 000000000000..2b7840533df2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.settings.brightness + +import android.hardware.display.DisplayManager +import android.os.Handler +import android.service.vr.IVrManager +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.DisplayTracker +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.settings.FakeSettings +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class BrightnessControllerTest : SysuiTestCase() { + + private val executor = FakeExecutor(FakeSystemClock()) + private val secureSettings = FakeSettings() + @Mock private lateinit var toggleSlider: ToggleSlider + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var displayTracker: DisplayTracker + @Mock private lateinit var displayManager: DisplayManager + @Mock private lateinit var iVrManager: IVrManager + + private lateinit var testableLooper: TestableLooper + + private lateinit var underTest: BrightnessController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + + underTest = + BrightnessController( + context, + toggleSlider, + userTracker, + displayTracker, + displayManager, + secureSettings, + iVrManager, + executor, + mock(), + Handler(testableLooper.looper) + ) + } + + @Test + fun registerCallbacksMultipleTimes_onlyOneRegistration() { + val repeats = 100 + repeat(repeats) { underTest.registerCallbacks() } + val messagesProcessed = testableLooper.processMessagesNonBlocking(repeats) + + verify(displayTracker).addBrightnessChangeCallback(any(), any()) + verify(iVrManager).registerListener(any()) + + assertThat(messagesProcessed).isEqualTo(1) + } + + @Test + fun unregisterCallbacksMultipleTimes_onlyOneUnregistration() { + val repeats = 100 + underTest.registerCallbacks() + testableLooper.processAllMessages() + + repeat(repeats) { underTest.unregisterCallbacks() } + val messagesProcessed = testableLooper.processMessagesNonBlocking(repeats) + + verify(displayTracker).removeCallback(any()) + verify(iVrManager).unregisterListener(any()) + + assertThat(messagesProcessed).isEqualTo(1) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt index 5c35913f6e20..ed1397ff7013 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.settings.brightness import android.content.Intent import android.graphics.Rect -import android.os.Handler import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.View @@ -29,8 +28,6 @@ import androidx.test.rule.ActivityTestRule import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.activity.SingleActivityFactory -import com.android.systemui.settings.FakeDisplayTracker -import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.FakeExecutor @@ -53,28 +50,24 @@ import org.mockito.MockitoAnnotations @TestableLooper.RunWithLooper class BrightnessDialogTest : SysuiTestCase() { - @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var brightnessSliderControllerFactory: BrightnessSliderController.Factory - @Mock private lateinit var backgroundHandler: Handler @Mock private lateinit var brightnessSliderController: BrightnessSliderController + @Mock private lateinit var brightnessControllerFactory: BrightnessController.Factory + @Mock private lateinit var brightnessController: BrightnessController @Mock private lateinit var accessibilityMgr: AccessibilityManagerWrapper private val clock = FakeSystemClock() private val mainExecutor = FakeExecutor(clock) - private var displayTracker = FakeDisplayTracker(mContext) - @Rule @JvmField var activityRule = ActivityTestRule( /* activityFactory= */ SingleActivityFactory { TestDialog( - userTracker, - displayTracker, brightnessSliderControllerFactory, + brightnessControllerFactory, mainExecutor, - backgroundHandler, accessibilityMgr ) }, @@ -88,6 +81,7 @@ class BrightnessDialogTest : SysuiTestCase() { `when`(brightnessSliderControllerFactory.create(any(), any())) .thenReturn(brightnessSliderController) `when`(brightnessSliderController.rootView).thenReturn(View(context)) + `when`(brightnessControllerFactory.create(any())).thenReturn(brightnessController) } @After @@ -178,19 +172,15 @@ class BrightnessDialogTest : SysuiTestCase() { } class TestDialog( - userTracker: UserTracker, - displayTracker: FakeDisplayTracker, brightnessSliderControllerFactory: BrightnessSliderController.Factory, + brightnessControllerFactory: BrightnessController.Factory, mainExecutor: DelayableExecutor, - backgroundHandler: Handler, accessibilityMgr: AccessibilityManagerWrapper ) : BrightnessDialog( - userTracker, - displayTracker, brightnessSliderControllerFactory, + brightnessControllerFactory, mainExecutor, - backgroundHandler, accessibilityMgr ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt new file mode 100644 index 000000000000..24d62fba8471 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import android.os.PowerManager +import android.testing.AndroidTestingRunner +import android.view.MotionEvent +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.power.data.repository.FakePowerRepository +import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +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.ArgumentMatchers +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidTestingRunner::class) +class LockscreenHostedDreamGestureListenerTest : SysuiTestCase() { + @Mock private lateinit var falsingManager: FalsingManager + @Mock private lateinit var falsingCollector: FalsingCollector + @Mock private lateinit var statusBarStateController: StatusBarStateController + @Mock private lateinit var shadeLogger: ShadeLogger + @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController + @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor + + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private lateinit var powerRepository: FakePowerRepository + private lateinit var keyguardRepository: FakeKeyguardRepository + private lateinit var underTest: LockscreenHostedDreamGestureListener + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + powerRepository = FakePowerRepository() + keyguardRepository = FakeKeyguardRepository() + + underTest = + LockscreenHostedDreamGestureListener( + falsingManager, + PowerInteractor( + powerRepository, + keyguardRepository, + falsingCollector, + screenOffAnimationController, + statusBarStateController, + ), + statusBarStateController, + primaryBouncerInteractor, + keyguardRepository, + shadeLogger, + ) + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + whenever(primaryBouncerInteractor.isBouncerShowing()).thenReturn(false) + } + + @Test + fun testGestureDetector_onSingleTap_whileDreaming() = + testScope.runTest { + // GIVEN device dreaming and the dream is hosted in lockscreen + whenever(statusBarStateController.isDreaming).thenReturn(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + testScope.runCurrent() + + // GIVEN the falsing manager does NOT think the tap is a false tap + whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(false) + + // WHEN there's a tap + underTest.onSingleTapUp(upEv) + + // THEN wake up device if dreaming + Truth.assertThat(powerRepository.lastWakeWhy).isNotNull() + Truth.assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_TAP) + } + + @Test + fun testGestureDetector_onSingleTap_notOnKeyguard() = + testScope.runTest { + // GIVEN device dreaming and the dream is hosted in lockscreen + whenever(statusBarStateController.isDreaming).thenReturn(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + testScope.runCurrent() + + // GIVEN shade is open + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE) + + // GIVEN the falsing manager does NOT think the tap is a false tap + whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(false) + + // WHEN there's a tap + underTest.onSingleTapUp(upEv) + + // THEN the falsing manager never gets a call + verify(falsingManager, never()).isFalseTap(ArgumentMatchers.anyInt()) + } + + @Test + fun testGestureDetector_onSingleTap_bouncerShown() = + testScope.runTest { + // GIVEN device dreaming and the dream is hosted in lockscreen + whenever(statusBarStateController.isDreaming).thenReturn(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + testScope.runCurrent() + + // GIVEN bouncer is expanded + whenever(primaryBouncerInteractor.isBouncerShowing()).thenReturn(true) + + // GIVEN the falsing manager does NOT think the tap is a false tap + whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(false) + + // WHEN there's a tap + underTest.onSingleTapUp(upEv) + + // THEN the falsing manager never gets a call + verify(falsingManager, never()).isFalseTap(ArgumentMatchers.anyInt()) + } + + @Test + fun testGestureDetector_onSingleTap_falsing() = + testScope.runTest { + // GIVEN device dreaming and the dream is hosted in lockscreen + whenever(statusBarStateController.isDreaming).thenReturn(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + testScope.runCurrent() + + // GIVEN the falsing manager thinks the tap is a false tap + whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(true) + + // WHEN there's a tap + underTest.onSingleTapUp(upEv) + + // THEN the device doesn't wake up + Truth.assertThat(powerRepository.lastWakeWhy).isNull() + Truth.assertThat(powerRepository.lastWakeReason).isNull() + } + + @Test + fun testSingleTap_notDreaming_noFalsingCheck() = + testScope.runTest { + // GIVEN device not dreaming with lockscreen hosted dream + whenever(statusBarStateController.isDreaming).thenReturn(false) + keyguardRepository.setIsActiveDreamLockscreenHosted(false) + testScope.runCurrent() + + // WHEN there's a tap + underTest.onSingleTapUp(upEv) + + // THEN the falsing manager never gets a call + verify(falsingManager, never()).isFalseTap(ArgumentMatchers.anyInt()) + } +} + +private val upEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0) 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 5fb3a7955b5c..2a398c55560c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -111,6 +111,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock private lateinit var lockIconViewController: LockIconViewController @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController @Mock private lateinit var pulsingGestureListener: PulsingGestureListener + @Mock + private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener @Mock private lateinit var notificationInsetsController: NotificationInsetsController @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @@ -147,6 +149,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { featureFlags.set(Flags.DUAL_SHADE, false) featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) + featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) val inputProxy = MultiShadeInputProxy() testScope = TestScope() @@ -183,6 +186,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { notificationInsetsController, ambientState, pulsingGestureListener, + mLockscreenHostedDreamGestureListener, keyguardBouncerViewModel, keyguardBouncerComponentFactory, mock(KeyguardMessageAreaController.Factory::class.java), diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 544137e95779..d9eb9b9166b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -113,6 +113,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController @Mock private lateinit var ambientState: AmbientState @Mock private lateinit var pulsingGestureListener: PulsingGestureListener + @Mock + private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel @Mock private lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock private lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @@ -161,6 +163,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { featureFlags.set(Flags.DUAL_SHADE, false) featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) + featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) val inputProxy = MultiShadeInputProxy() testScope = TestScope() val multiShadeInteractor = @@ -196,6 +199,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { notificationInsetsController, ambientState, pulsingGestureListener, + mLockscreenHostedDreamGestureListener, keyguardBouncerViewModel, keyguardBouncerComponentFactory, Mockito.mock(KeyguardMessageAreaController.Factory::class.java), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt new file mode 100644 index 000000000000..a544cad03b77 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt @@ -0,0 +1,166 @@ +/* + * 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. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.collection.coordinator + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class DreamCoordinatorTest : SysuiTestCase() { + @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController + @Mock private lateinit var notifPipeline: NotifPipeline + @Mock private lateinit var filterListener: Pluggable.PluggableListener<NotifFilter> + + private val keyguardRepository = FakeKeyguardRepository() + private var fakeEntry: NotificationEntry = NotificationEntryBuilder().build() + val testDispatcher = UnconfinedTestDispatcher() + val testScope = TestScope(testDispatcher) + + private lateinit var filter: NotifFilter + private lateinit var statusBarListener: StatusBarStateController.StateListener + private lateinit var dreamCoordinator: DreamCoordinator + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + // Build the coordinator + dreamCoordinator = + DreamCoordinator( + statusBarStateController, + testScope.backgroundScope, + keyguardRepository + ) + + // Attach the pipeline and capture the listeners/filters that it registers + dreamCoordinator.attach(notifPipeline) + + filter = withArgCaptor { verify(notifPipeline).addPreGroupFilter(capture()) } + filter.setInvalidationListener(filterListener) + + statusBarListener = withArgCaptor { + verify(statusBarStateController).addCallback(capture()) + } + } + + @Test + fun hideNotifications_whenDreamingAndOnKeyguard() = + testScope.runTest { + // GIVEN we are on keyguard and not dreaming + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(false) + runCurrent() + + // THEN notifications are not filtered out + verifyPipelinesNotInvalidated() + assertThat(filter.shouldFilterOut(fakeEntry, 0L)).isFalse() + + // WHEN dreaming starts and the active dream is hosted in lockscreen + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + runCurrent() + + // THEN pipeline is notified and notifications should all be filtered out + verifyPipelinesInvalidated() + assertThat(filter.shouldFilterOut(fakeEntry, 0L)).isTrue() + } + + @Test + fun showNotifications_whenDreamingAndNotOnKeyguard() = + testScope.runTest { + // GIVEN we are on the keyguard and active dream is hosted in lockscreen + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + runCurrent() + + // THEN pipeline is notified and notifications are all filtered out + verifyPipelinesInvalidated() + clearPipelineInvocations() + assertThat(filter.shouldFilterOut(fakeEntry, 0L)).isTrue() + + // WHEN we are no longer on the keyguard + statusBarListener.onStateChanged(StatusBarState.SHADE) + + // THEN pipeline is notified and notifications are not filtered out + verifyPipelinesInvalidated() + assertThat(filter.shouldFilterOut(fakeEntry, 0L)).isFalse() + } + + @Test + fun showNotifications_whenOnKeyguardAndNotDreaming() = + testScope.runTest { + // GIVEN we are on the keyguard and active dream is hosted in lockscreen + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + runCurrent() + + // THEN pipeline is notified and notifications are all filtered out + verifyPipelinesInvalidated() + clearPipelineInvocations() + assertThat(filter.shouldFilterOut(fakeEntry, 0L)).isTrue() + + // WHEN the lockscreen hosted dream stops + keyguardRepository.setIsActiveDreamLockscreenHosted(false) + runCurrent() + + // THEN pipeline is notified and notifications are not filtered out + verifyPipelinesInvalidated() + assertThat(filter.shouldFilterOut(fakeEntry, 0L)).isFalse() + } + + private fun verifyPipelinesInvalidated() { + verify(filterListener).onPluggableInvalidated(eq(filter), any()) + } + + private fun verifyPipelinesNotInvalidated() { + verify(filterListener, never()).onPluggableInvalidated(eq(filter), any()) + } + + private fun clearPipelineInvocations() { + clearInvocations(filterListener) + } +} 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 608778e05dad..1dc8453a90ec 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 @@ -27,6 +27,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -87,6 +88,7 @@ import java.util.function.Consumer; @RunWithLooper public class ExpandableNotificationRowTest extends SysuiTestCase { + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); private NotificationTestHelper mNotificationTestHelper; @Rule public MockitoRule mockito = MockitoJUnit.rule(); @@ -96,12 +98,10 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { mNotificationTestHelper = new NotificationTestHelper( mContext, mDependency, - TestableLooper.get(this)); + TestableLooper.get(this), + mFeatureFlags); mNotificationTestHelper.setDefaultInflationFlags(FLAG_CONTENT_VIEW_ALL); - - FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags(); - fakeFeatureFlags.set(Flags.SENSITIVE_REVEAL_ANIM, false); - mNotificationTestHelper.setFeatureFlags(fakeFeatureFlags); + mFeatureFlags.setDefault(Flags.SENSITIVE_REVEAL_ANIM); } @Test @@ -183,6 +183,14 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { } @Test + public void testSetSensitiveOnNotifRowNotifiesOfHeightChange_withOtherFlagValue() + throws Exception { + FakeFeatureFlags flags = mFeatureFlags; + flags.set(Flags.SENSITIVE_REVEAL_ANIM, !flags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)); + testSetSensitiveOnNotifRowNotifiesOfHeightChange(); + } + + @Test public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws Exception { // GIVEN a sensitive notification row that's currently redacted ExpandableNotificationRow row = mNotificationTestHelper.createRow(); @@ -199,10 +207,19 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { // WHEN the row is set to no longer be sensitive row.setSensitive(false, true); + boolean expectAnimation = mFeatureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM); // VERIFY that the height change listener is invoked assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPrivateLayout()); assertThat(row.getIntrinsicHeight()).isGreaterThan(0); - verify(listener).onHeightChanged(eq(row), eq(false)); + verify(listener).onHeightChanged(eq(row), eq(expectAnimation)); + } + + @Test + public void testSetSensitiveOnGroupRowNotifiesOfHeightChange_withOtherFlagValue() + throws Exception { + FakeFeatureFlags flags = mFeatureFlags; + flags.set(Flags.SENSITIVE_REVEAL_ANIM, !flags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)); + testSetSensitiveOnGroupRowNotifiesOfHeightChange(); } @Test @@ -222,10 +239,19 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { // WHEN the row is set to no longer be sensitive group.setSensitive(false, true); + boolean expectAnimation = mFeatureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM); // VERIFY that the height change listener is invoked assertThat(group.getShowingLayout()).isSameInstanceAs(group.getPrivateLayout()); assertThat(group.getIntrinsicHeight()).isGreaterThan(0); - verify(listener).onHeightChanged(eq(group), eq(false)); + verify(listener).onHeightChanged(eq(group), eq(expectAnimation)); + } + + @Test + public void testSetSensitiveOnPublicRowDoesNotNotifyOfHeightChange_withOtherFlagValue() + throws Exception { + FakeFeatureFlags flags = mFeatureFlags; + flags.set(Flags.SENSITIVE_REVEAL_ANIM, !flags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)); + testSetSensitiveOnPublicRowDoesNotNotifyOfHeightChange(); } @Test @@ -254,7 +280,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { assertThat(publicRow.getIntrinsicHeight()).isGreaterThan(0); assertThat(publicRow.getPrivateLayout().getMinHeight()) .isEqualTo(publicRow.getPublicLayout().getMinHeight()); - verify(listener, never()).onHeightChanged(eq(publicRow), eq(false)); + verify(listener, never()).onHeightChanged(eq(publicRow), anyBoolean()); } private void measureAndLayout(ExpandableNotificationRow row) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 1a644d3540b0..d21029d33d5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -48,12 +48,16 @@ import android.text.TextUtils; import android.view.LayoutInflater; import android.widget.RemoteViews; +import androidx.annotation.NonNull; + import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.TestableDependency; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.media.controls.util.MediaFeatureFlag; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -90,6 +94,7 @@ import com.android.systemui.wmshell.BubblesTestActivity; import org.mockito.ArgumentCaptor; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -130,14 +135,24 @@ public class NotificationTestHelper { private final NotificationDismissibilityProvider mDismissibilityProvider; public final Runnable mFutureDismissalRunnable; private @InflationFlag int mDefaultInflationFlags; - private FeatureFlags mFeatureFlags; + private final FakeFeatureFlags mFeatureFlags; public NotificationTestHelper( Context context, TestableDependency dependency, TestableLooper testLooper) { + this(context, dependency, testLooper, new FakeFeatureFlags()); + } + + public NotificationTestHelper( + Context context, + TestableDependency dependency, + TestableLooper testLooper, + @NonNull FakeFeatureFlags featureFlags) { mContext = context; mTestLooper = testLooper; + mFeatureFlags = Objects.requireNonNull(featureFlags); + dependency.injectTestDependency(FeatureFlags.class, mFeatureFlags); dependency.injectMockDependency(NotificationMediaManager.class); dependency.injectMockDependency(NotificationShadeWindowController.class); dependency.injectMockDependency(MediaOutputDialogFactory.class); @@ -183,17 +198,12 @@ public class NotificationTestHelper { mFutureDismissalRunnable = mock(Runnable.class); when(mOnUserInteractionCallback.registerFutureDismissal(any(), anyInt())) .thenReturn(mFutureDismissalRunnable); - mFeatureFlags = mock(FeatureFlags.class); } public void setDefaultInflationFlags(@InflationFlag int defaultInflationFlags) { mDefaultInflationFlags = defaultInflationFlags; } - public void setFeatureFlags(FeatureFlags featureFlags) { - mFeatureFlags = featureFlags; - } - public ExpandableNotificationRowLogger getMockLogger() { return mMockLogger; } @@ -527,6 +537,10 @@ public class NotificationTestHelper { @InflationFlag int extraInflationFlags, int importance) throws Exception { + // NOTE: This flag is read when the ExpandableNotificationRow is inflated, so it needs to be + // set, but we do not want to override an existing value that is needed by a specific test. + mFeatureFlags.setDefault(Flags.IMPROVED_HUN_ANIMATIONS); + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( mContext.LAYOUT_INFLATER_SERVICE); mRow = (ExpandableNotificationRow) inflater.inflate( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt index 09382ec1945e..3d752880f423 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt @@ -20,7 +20,6 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FeatureFlags import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager @@ -42,7 +41,6 @@ class AmbientStateTest : SysuiTestCase() { private val bypassController = StackScrollAlgorithm.BypassController { false } private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>() private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>() - private val featureFlags = mock<FeatureFlags>() private lateinit var sut: AmbientState @@ -55,8 +53,7 @@ class AmbientStateTest : SysuiTestCase() { sectionProvider, bypassController, statusBarKeyguardViewManager, - largeScreenShadeInterpolator, - featureFlags + largeScreenShadeInterpolator ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index f38881c5b521..4b145d8b0dd2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -30,7 +30,6 @@ import android.view.ViewGroup; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.controls.ui.KeyguardMediaController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; @@ -65,7 +64,6 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Mock private SectionHeaderController mPeopleHeaderController; @Mock private SectionHeaderController mAlertingHeaderController; @Mock private SectionHeaderController mSilentHeaderController; - @Mock private FeatureFlags mFeatureFlag; private NotificationSectionsManager mSectionsManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt index 8d751e3b2808..1dc0ab07349b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt @@ -9,7 +9,9 @@ import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerPr import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ShadeInterpolation +import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.NotificationShelf import com.android.systemui.statusbar.StatusBarIconView @@ -20,6 +22,7 @@ import com.android.systemui.util.mockito.mock import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -34,22 +37,32 @@ import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper -class NotificationShelfTest : SysuiTestCase() { +open class NotificationShelfTest : SysuiTestCase() { + + open val useShelfRefactor: Boolean = false + open val useSensitiveReveal: Boolean = false + private val flags = FakeFeatureFlags() @Mock private lateinit var largeScreenShadeInterpolator: LargeScreenShadeInterpolator @Mock - private lateinit var flags: FeatureFlags - @Mock private lateinit var ambientState: AmbientState @Mock private lateinit var hostLayoutController: NotificationStackScrollLayoutController + @Mock + private lateinit var hostLayout: NotificationStackScrollLayout + @Mock + private lateinit var roundnessManager: NotificationRoundnessManager private lateinit var shelf: NotificationShelf @Before fun setUp() { MockitoAnnotations.initMocks(this) + mDependency.injectTestDependency(FeatureFlags::class.java, flags) + flags.set(Flags.NOTIFICATION_SHELF_REFACTOR, useShelfRefactor) + flags.set(Flags.SENSITIVE_REVEAL_ANIM, useSensitiveReveal) + flags.setDefault(Flags.IMPROVED_HUN_ANIMATIONS) val root = FrameLayout(context) shelf = LayoutInflater.from(root.context) .inflate(/* resource = */ R.layout.status_bar_notification_shelf, @@ -57,10 +70,13 @@ class NotificationShelfTest : SysuiTestCase() { /* attachToRoot = */false) as NotificationShelf whenever(ambientState.largeScreenShadeInterpolator).thenReturn(largeScreenShadeInterpolator) - whenever(ambientState.featureFlags).thenReturn(flags) whenever(ambientState.isSmallScreen).thenReturn(true) - shelf.bind(ambientState, /* hostLayoutController */ hostLayoutController) + if (useShelfRefactor) { + shelf.bind(ambientState, hostLayout, roundnessManager) + } else { + shelf.bind(ambientState, hostLayoutController) + } shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5) } @@ -345,7 +361,7 @@ class NotificationShelfTest : SysuiTestCase() { @Test fun updateState_withNullLastVisibleBackgroundChild_hideShelf() { // GIVEN - shelf.setSensitiveRevealAnimEnabled(true) + assumeTrue(useSensitiveReveal) whenever(ambientState.stackY).thenReturn(100f) whenever(ambientState.stackHeight).thenReturn(100f) val paddingBetweenElements = @@ -372,7 +388,7 @@ class NotificationShelfTest : SysuiTestCase() { @Test fun updateState_withNullFirstViewInShelf_hideShelf() { // GIVEN - shelf.setSensitiveRevealAnimEnabled(true) + assumeTrue(useSensitiveReveal) whenever(ambientState.stackY).thenReturn(100f) whenever(ambientState.stackHeight).thenReturn(100f) val paddingBetweenElements = @@ -399,7 +415,7 @@ class NotificationShelfTest : SysuiTestCase() { @Test fun updateState_withCollapsedShade_hideShelf() { // GIVEN - shelf.setSensitiveRevealAnimEnabled(true) + assumeTrue(useSensitiveReveal) whenever(ambientState.stackY).thenReturn(100f) whenever(ambientState.stackHeight).thenReturn(100f) val paddingBetweenElements = @@ -426,7 +442,7 @@ class NotificationShelfTest : SysuiTestCase() { @Test fun updateState_withHiddenSectionBeforeShelf_hideShelf() { // GIVEN - shelf.setSensitiveRevealAnimEnabled(true) + assumeTrue(useSensitiveReveal) whenever(ambientState.stackY).thenReturn(100f) whenever(ambientState.stackHeight).thenReturn(100f) val paddingBetweenElements = @@ -486,3 +502,25 @@ class NotificationShelfTest : SysuiTestCase() { assertEquals(expectedAlpha, shelf.viewState.alpha) } } + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class NotificationShelfWithRefactorTest : NotificationShelfTest() { + override val useShelfRefactor: Boolean = true +} + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class NotificationShelfWithSensitiveRevealTest : NotificationShelfTest() { + override val useSensitiveReveal: Boolean = true +} + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class NotificationShelfWithBothFlagsTest : NotificationShelfTest() { + override val useShelfRefactor: Boolean = true + override val useSensitiveReveal: Boolean = true +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index ee8325ec02b5..07eadf7c9bb4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -54,7 +54,6 @@ import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; @@ -119,6 +118,7 @@ import java.util.Optional; @RunWith(AndroidTestingRunner.class) public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Mock private NotificationGutsManager mNotificationGutsManager; @Mock private NotificationsController mNotificationsController; @Mock private NotificationVisibilityProvider mVisibilityProvider; @@ -157,7 +157,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private StackStateLogger mStackLogger; @Mock private NotificationStackScrollLogger mLogger; @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator; - private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Mock private NotificationTargetsHelper mNotificationTargetsHelper; @Mock private SecureSettings mSecureSettings; @Mock private NotificationIconAreaController mIconAreaController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 8ad271bef2e4..72fcdec3c44c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -68,7 +68,9 @@ import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; import com.android.systemui.statusbar.EmptyShadeView; @@ -106,6 +108,7 @@ import java.util.ArrayList; @TestableLooper.RunWithLooper public class NotificationStackScrollLayoutTest extends SysuiTestCase { + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); private NotificationStackScrollLayout mStackScroller; // Normally test this private NotificationStackScrollLayout mStackScrollerInternal; // See explanation below private AmbientState mAmbientState; @@ -129,7 +132,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator; - @Mock private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { @@ -143,11 +145,25 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mNotificationSectionsManager, mBypassController, mStatusBarKeyguardViewManager, - mLargeScreenShadeInterpolator, - mFeatureFlags + mLargeScreenShadeInterpolator )); + // Register the debug flags we use + assertFalse(Flags.NSSL_DEBUG_LINES.getDefault()); + assertFalse(Flags.NSSL_DEBUG_REMOVE_ANIMATION.getDefault()); + mFeatureFlags.set(Flags.NSSL_DEBUG_LINES, false); + mFeatureFlags.set(Flags.NSSL_DEBUG_REMOVE_ANIMATION, false); + + // Register the feature flags we use + // TODO: Ideally we wouldn't need to set these unless a test actually reads them, + // and then we would test both configurations, but currently they are all read + // in the constructor. + mFeatureFlags.setDefault(Flags.SENSITIVE_REVEAL_ANIM); + mFeatureFlags.setDefault(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS); + mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR); + // Inject dependencies before initializing the layout + mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags); mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); mDependency.injectMockDependency(ShadeController.class); mDependency.injectTestDependency( @@ -176,13 +192,18 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper, mNotificationStackSizeCalculator); mStackScroller = spy(mStackScrollerInternal); - mStackScroller.setShelfController(notificationShelfController); + if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + mStackScroller.setShelfController(notificationShelfController); + } mStackScroller.setNotificationsController(mNotificationsController); mStackScroller.setEmptyShadeView(mEmptyShadeView); when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(true); when(mStackScrollLayoutController.getNotificationRoundnessManager()) .thenReturn(mNotificationRoundnessManager); mStackScroller.setController(mStackScrollLayoutController); + if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + mStackScroller.setShelf(mNotificationShelf); + } doNothing().when(mGroupExpansionManager).collapseGroups(); doNothing().when(mExpandHelper).cancelImmediately(); @@ -899,7 +920,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testWindowInsetAnimationProgress_updatesBottomInset() { int bottomImeInset = 100; - mStackScrollerInternal.setAnimatedInsetsEnabled(true); WindowInsets windowInsets = new WindowInsets.Builder() .setInsets(ime(), Insets.of(0, 0, 0, bottomImeInset)).build(); ArrayList<WindowInsetsAnimation> windowInsetsAnimations = new ArrayList<>(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index df65c09eb8a9..85a2bdd21073 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -47,6 +47,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; @@ -83,7 +84,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { private Handler mHandler; private ExpandableNotificationRow mNotificationRow; private Runnable mFalsingCheck; - private FeatureFlags mFeatureFlags; + private final FeatureFlags mFeatureFlags = new FakeFeatureFlags(); private static final int FAKE_ROW_WIDTH = 20; private static final int FAKE_ROW_HEIGHT = 20; @@ -96,7 +97,6 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { mCallback = mock(NotificationSwipeHelper.NotificationCallback.class); mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class); mNotificationRoundnessManager = mock(NotificationRoundnessManager.class); - mFeatureFlags = mock(FeatureFlags.class); mSwipeHelper = spy(new NotificationSwipeHelper( mContext.getResources(), ViewConfiguration.get(mContext), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt index 45725ced521c..e30947ce84bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt @@ -18,6 +18,7 @@ import org.junit.runner.RunWith @RunWith(AndroidTestingRunner::class) @RunWithLooper class NotificationTargetsHelperTest : SysuiTestCase() { + private val featureFlags = FakeFeatureFlags() lateinit var notificationTestHelper: NotificationTestHelper private val sectionsManager: NotificationSectionsManager = mock() private val stackScrollLayout: NotificationStackScrollLayout = mock() @@ -26,10 +27,10 @@ class NotificationTargetsHelperTest : SysuiTestCase() { fun setUp() { allowTestableLooperAsMainThread() notificationTestHelper = - NotificationTestHelper(mContext, mDependency, TestableLooper.get(this)) + NotificationTestHelper(mContext, mDependency, TestableLooper.get(this), featureFlags) } - private fun notificationTargetsHelper() = NotificationTargetsHelper(FakeFeatureFlags()) + private fun notificationTargetsHelper() = NotificationTargetsHelper(featureFlags) @Test fun targetsForFirstNotificationInGroup() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 4c97d20c5da8..987861d3f133 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -8,7 +8,6 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ShadeInterpolation.getContentAlpha import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FeatureFlags import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.EmptyShadeView import com.android.systemui.statusbar.NotificationShelf @@ -45,7 +44,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { private val dumpManager = mock<DumpManager>() private val mStatusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>() private val notificationShelf = mock<NotificationShelf>() - private val featureFlags = mock<FeatureFlags>() private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply { layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100) } @@ -56,7 +54,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* bypassController */ { false }, mStatusBarKeyguardViewManager, largeScreenShadeInterpolator, - featureFlags, ) private val testableResources = mContext.getOrCreateTestableResources() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index 89f8bdbfe05b..479803e1dfac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -142,7 +142,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle, mAuthController, mStatusBarStateController, mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper, - mSystemClock + mSystemClock, + mStatusBarKeyguardViewManager ); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mBiometricUnlockController.addListener(mBiometricUnlockEventsListener); @@ -464,6 +465,69 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test + public void onSideFingerprintSuccess_dreaming_unlockThenWake() { + when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); + when(mWakefulnessLifecycle.getLastWakeReason()) + .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON); + final ArgumentCaptor<Runnable> afterKeyguardGoneRunnableCaptor = + ArgumentCaptor.forClass(Runnable.class); + givenDreamingLocked(); + mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT, true); + + // Make sure the BiometricUnlockController has registered a callback for when the keyguard + // is gone + verify(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable( + afterKeyguardGoneRunnableCaptor.capture()); + // Ensure that the power hasn't been told to wake up yet. + verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString()); + // Check that the keyguard has been told to unlock. + verify(mKeyguardViewMediator).onWakeAndUnlocking(); + + // Simulate the keyguard disappearing. + afterKeyguardGoneRunnableCaptor.getValue().run(); + // Verify that the power manager has been told to wake up now. + verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString()); + } + + @Test + public void onSideFingerprintSuccess_dreaming_unlockIfStillLockedNotDreaming() { + when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); + when(mWakefulnessLifecycle.getLastWakeReason()) + .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON); + final ArgumentCaptor<Runnable> afterKeyguardGoneRunnableCaptor = + ArgumentCaptor.forClass(Runnable.class); + givenDreamingLocked(); + mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT, true); + + // Make sure the BiometricUnlockController has registered a callback for when the keyguard + // is gone + verify(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable( + afterKeyguardGoneRunnableCaptor.capture()); + // Ensure that the power hasn't been told to wake up yet. + verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString()); + // Check that the keyguard has been told to unlock. + verify(mKeyguardViewMediator).onWakeAndUnlocking(); + + when(mUpdateMonitor.isDreaming()).thenReturn(false); + when(mKeyguardStateController.isUnlocked()).thenReturn(false); + + // Simulate the keyguard disappearing. + afterKeyguardGoneRunnableCaptor.getValue().run(); + + final ArgumentCaptor<Runnable> dismissKeyguardRunnableCaptor = + ArgumentCaptor.forClass(Runnable.class); + verify(mHandler).post(dismissKeyguardRunnableCaptor.capture()); + + // Verify that the power manager was not told to wake up. + verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString()); + + dismissKeyguardRunnableCaptor.getValue().run(); + // Verify that the keyguard controller is told to unlock. + verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false)); + } + + + @Test public void onSideFingerprintSuccess_oldPowerButtonPress_playHaptic() { // GIVEN side fingerprint enrolled, last wake reason was power button when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); @@ -537,6 +601,11 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean()); } + private void givenDreamingLocked() { + when(mUpdateMonitor.isDreaming()).thenReturn(true); + when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); + } + private void givenFingerprintModeUnlockCollapsing() { when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 3d35233ad646..530085191e96 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -129,7 +129,6 @@ import com.android.systemui.settings.brightness.BrightnessSliderController; import com.android.systemui.shade.CameraLauncher; import com.android.systemui.shade.NotificationPanelView; import com.android.systemui.shade.NotificationPanelViewController; -import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeController; @@ -252,7 +251,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy; - @Mock private NotificationShadeWindowView mNotificationShadeWindowView; @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock private AssistManager mAssistManager; @Mock private NotificationGutsManager mNotificationGutsManager; @@ -276,6 +274,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController; + @Mock private Lazy<NotificationShadeWindowViewController> + mNotificationShadeWindowViewControllerLazy; @Mock private NotificationShelfController mNotificationShelfController; @Mock private DozeParameters mDozeParameters; @Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy; @@ -428,10 +428,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper); when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController); when(mCameraLauncherLazy.get()).thenReturn(mCameraLauncher); + when(mNotificationShadeWindowViewControllerLazy.get()) + .thenReturn(mNotificationShadeWindowViewController); when(mStatusBarComponentFactory.create()).thenReturn(mCentralSurfacesComponent); - when(mCentralSurfacesComponent.getNotificationShadeWindowViewController()).thenReturn( - mNotificationShadeWindowViewController); doAnswer(invocation -> { ((Runnable) invocation.getArgument(0)).run(); return null; @@ -510,6 +510,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { () -> mAssistManager, configurationController, mNotificationShadeWindowController, + mNotificationShadeWindowViewControllerLazy, mNotificationShelfController, mStackScrollerController, mDozeParameters, @@ -586,9 +587,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { when(mKeyguardViewMediator.getViewMediatorCallback()).thenReturn( mKeyguardVieMediatorCallback); - // TODO: we should be able to call mCentralSurfaces.start() and have all the below values - // initialized automatically and make NPVC private. - mCentralSurfaces.mNotificationShadeWindowView = mNotificationShadeWindowView; + // TODO(b/277764509): we should be able to call mCentralSurfaces.start() and have all the + // below values initialized automatically. mCentralSurfaces.mDozeScrimController = mDozeScrimController; mCentralSurfaces.mPresenter = mNotificationPresenter; mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController; @@ -823,8 +823,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { */ @Test public void testPredictiveBackCallback_invocationCollapsesPanel() { - mCentralSurfaces.setNotificationShadeWindowViewController( - mNotificationShadeWindowViewController); mCentralSurfaces.handleVisibleToUserChanged(true); verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback( eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), @@ -841,8 +839,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { */ @Test public void testPredictiveBackAnimation_progressMaxScalesPanel() { - mCentralSurfaces.setNotificationShadeWindowViewController( - mNotificationShadeWindowViewController); mCentralSurfaces.handleVisibleToUserChanged(true); verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback( eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), @@ -864,8 +860,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { */ @Test public void testPredictiveBackAnimation_progressMinScalesPanel() { - mCentralSurfaces.setNotificationShadeWindowViewController( - mNotificationShadeWindowViewController); mCentralSurfaces.handleVisibleToUserChanged(true); verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback( eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 2d96e594592c..c8ec1bf4af9f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -204,6 +204,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { userChipViewModel, centralSurfacesImpl, shadeControllerImpl, + shadeViewController, shadeLogger, viewUtil, configurationController diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 9c7f6190de44..33144f233a71 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -64,7 +64,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.classifier.FalsingCollectorFake; -import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; @@ -117,6 +117,7 @@ import java.util.Optional; public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private static final int DISPLAY_ID = 0; + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Mock private AssistManager mAssistManager; @@ -256,7 +257,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { notificationAnimationProvider, mock(LaunchFullScreenIntentProvider.class), mPowerInteractor, - mock(FeatureFlags.class), + mFeatureFlags, mUserTracker ); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 5bd6ff4e73f2..9c52788dc2eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -42,7 +42,6 @@ import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeController; -import com.android.systemui.shade.ShadeNotificationPresenter; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.LockscreenShadeTransitionController; @@ -52,7 +51,6 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; @@ -81,19 +79,15 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { private CommandQueue mCommandQueue; private FakeMetricsLogger mMetricsLogger; private final ShadeController mShadeController = mock(ShadeController.class); - private final CentralSurfaces mCentralSurfaces = mock(CentralSurfaces.class); private final NotificationsInteractor mNotificationsInteractor = mock(NotificationsInteractor.class); private final KeyguardStateController mKeyguardStateController = mock(KeyguardStateController.class); - private final NotifPipelineFlags mNotifPipelineFlags = mock(NotifPipelineFlags.class); private final InitController mInitController = new InitController(); @Before public void setup() { mMetricsLogger = new FakeMetricsLogger(); - LockscreenGestureLogger lockscreenGestureLogger = new LockscreenGestureLogger( - mMetricsLogger); mCommandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext)); mDependency.injectTestDependency(StatusBarStateController.class, mock(SysuiStatusBarStateController.class)); @@ -111,8 +105,6 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); ShadeViewController shadeViewController = mock(ShadeViewController.class); - when(shadeViewController.getShadeNotificationPresenter()) - .thenReturn(mock(ShadeNotificationPresenter.class)); mStatusBarNotificationPresenter = new StatusBarNotificationPresenter( mContext, shadeViewController, @@ -125,7 +117,6 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class), mKeyguardStateController, - mCentralSurfaces, mNotificationsInteractor, mock(LockscreenShadeTransitionController.class), mock(PowerInteractor.class), @@ -135,11 +126,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotifShadeEventSource.class), mock(NotificationMediaManager.class), mock(NotificationGutsManager.class), - lockscreenGestureLogger, mInitController, mNotificationInterruptStateProvider, mock(NotificationRemoteInputManager.class), - mNotifPipelineFlags, mock(NotificationRemoteInputManager.Callback.class), mock(NotificationListContainer.class)); mInitController.executePostInitTasks(); @@ -211,7 +200,6 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { when(mKeyguardStateController.isShowing()).thenReturn(true); when(mKeyguardStateController.isOccluded()).thenReturn(false); - when(mCentralSurfaces.isOccluded()).thenReturn(false); assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(entry)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java index 391c8ca4d286..7c285b8aa1a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java @@ -102,6 +102,8 @@ public class RemoteInputViewTest extends SysuiTestCase { "com.android.sysuitest.dummynotificationsender"; private static final int DUMMY_MESSAGE_APP_ID = Process.LAST_APPLICATION_UID - 1; + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); + @Mock private RemoteInputController mController; @Mock private ShortcutManager mShortcutManager; @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; @@ -453,8 +455,7 @@ public class RemoteInputViewTest extends SysuiTestCase { private RemoteInputViewController bindController( RemoteInputView view, NotificationEntry entry) { - FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags(); - fakeFeatureFlags.set(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION, true); + mFeatureFlags.set(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION, true); RemoteInputViewControllerImpl viewController = new RemoteInputViewControllerImpl( view, entry, @@ -462,7 +463,7 @@ public class RemoteInputViewTest extends SysuiTestCase { mController, mShortcutManager, mUiEventLoggerFake, - fakeFeatureFlags + mFeatureFlags ); viewController.bind(); return viewController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt index d8e418a7815c..b13cb72dc944 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt @@ -26,6 +26,7 @@ import android.view.ViewRootImpl import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.util.mockito.eq +import com.android.systemui.wallpapers.data.repository.FakeWallpaperRepository import org.junit.Before import org.junit.Rule import org.junit.Test @@ -56,6 +57,7 @@ class WallpaperControllerTest : SysuiTestCase() { private lateinit var viewRootImpl: ViewRootImpl @Mock private lateinit var windowToken: IBinder + private val wallpaperRepository = FakeWallpaperRepository() @JvmField @Rule @@ -69,7 +71,7 @@ class WallpaperControllerTest : SysuiTestCase() { `when`(root.windowToken).thenReturn(windowToken) `when`(root.isAttachedToWindow).thenReturn(true) - wallaperController = WallpaperController(wallpaperManager) + wallaperController = WallpaperController(wallpaperManager, wallpaperRepository) wallaperController.rootView = root } @@ -90,9 +92,9 @@ class WallpaperControllerTest : SysuiTestCase() { @Test fun setUnfoldTransitionZoom_defaultUnfoldTransitionIsDisabled_doesNotUpdateWallpaperZoom() { - wallaperController.onWallpaperInfoUpdated(createWallpaperInfo( + wallpaperRepository.wallpaperInfo.value = createWallpaperInfo( useDefaultTransition = false - )) + ) wallaperController.setUnfoldTransitionZoom(0.5f) diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 0c77529377ab..c81910855f78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -16,6 +16,7 @@ package com.android.systemui.volume; +import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION; import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN; import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN; import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS; @@ -51,6 +52,7 @@ import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.VolumeDialogController; @@ -117,6 +119,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { } }; + private FakeFeatureFlags mFeatureFlags; + @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); @@ -132,6 +136,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mConfigurationController = new FakeConfigurationController(); + mFeatureFlags = new FakeFeatureFlags(); + mDialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, @@ -146,7 +152,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mCsdWarningDialogFactory, mPostureController, mTestableLooper.getLooper(), - mDumpManager); + mDumpManager, + mFeatureFlags); mDialog.init(0, null); State state = createShellState(); mDialog.onStateChangedH(state); @@ -254,6 +261,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Test public void testVibrateOnRingerChangedToVibrate() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); final State initialSilentState = new State(); initialSilentState.ringerModeInternal = AudioManager.RINGER_MODE_SILENT; @@ -274,7 +282,30 @@ public class VolumeDialogImplTest extends SysuiTestCase { } @Test + public void testControllerDoesNotVibrateOnRingerChangedToVibrate_OnewayAPI_On() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); + final State initialSilentState = new State(); + initialSilentState.ringerModeInternal = AudioManager.RINGER_MODE_SILENT; + + final State vibrateState = new State(); + vibrateState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE; + + // change ringer to silent + mDialog.onStateChangedH(initialSilentState); + + // expected: shouldn't call vibrate yet + verify(mVolumeDialogController, never()).vibrate(any()); + + // changed ringer to vibrate + mDialog.onStateChangedH(vibrateState); + + // expected: vibrate method of controller is not used + verify(mVolumeDialogController, never()).vibrate(any()); + } + + @Test public void testNoVibrateOnRingerInitialization() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); final State initialUnsetState = new State(); initialUnsetState.ringerModeInternal = -1; @@ -292,7 +323,42 @@ public class VolumeDialogImplTest extends SysuiTestCase { } @Test + public void testControllerDoesNotVibrateOnRingerInitialization_OnewayAPI_On() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); + final State initialUnsetState = new State(); + initialUnsetState.ringerModeInternal = -1; + + // ringer not initialized yet: + mDialog.onStateChangedH(initialUnsetState); + + final State vibrateState = new State(); + vibrateState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE; + + // changed ringer to vibrate + mDialog.onStateChangedH(vibrateState); + + // shouldn't call vibrate on the controller either + verify(mVolumeDialogController, never()).vibrate(any()); + } + + @Test public void testSelectVibrateFromDrawer() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); + final State initialUnsetState = new State(); + initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL; + mDialog.onStateChangedH(initialUnsetState); + + mActiveRinger.performClick(); + mDrawerVibrate.performClick(); + + // Make sure we've actually changed the ringer mode. + verify(mVolumeDialogController, times(1)).setRingerMode( + AudioManager.RINGER_MODE_VIBRATE, false); + } + + @Test + public void testSelectVibrateFromDrawer_OnewayAPI_On() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); final State initialUnsetState = new State(); initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL; mDialog.onStateChangedH(initialUnsetState); @@ -307,6 +373,22 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Test public void testSelectMuteFromDrawer() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); + final State initialUnsetState = new State(); + initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL; + mDialog.onStateChangedH(initialUnsetState); + + mActiveRinger.performClick(); + mDrawerMute.performClick(); + + // Make sure we've actually changed the ringer mode. + verify(mVolumeDialogController, times(1)).setRingerMode( + AudioManager.RINGER_MODE_SILENT, false); + } + + @Test + public void testSelectMuteFromDrawer_OnewayAPI_On() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); final State initialUnsetState = new State(); initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL; mDialog.onStateChangedH(initialUnsetState); @@ -321,6 +403,22 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Test public void testSelectNormalFromDrawer() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false); + final State initialUnsetState = new State(); + initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE; + mDialog.onStateChangedH(initialUnsetState); + + mActiveRinger.performClick(); + mDrawerNormal.performClick(); + + // Make sure we've actually changed the ringer mode. + verify(mVolumeDialogController, times(1)).setRingerMode( + AudioManager.RINGER_MODE_NORMAL, false); + } + + @Test + public void testSelectNormalFromDrawer_OnewayAPI_On() { + mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); final State initialUnsetState = new State(); initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE; mDialog.onStateChangedH(initialUnsetState); @@ -383,7 +481,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), - mDumpManager + mDumpManager, + mFeatureFlags ); dialog.init(0 , null); @@ -423,7 +522,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), - mDumpManager + mDumpManager, + mFeatureFlags ); dialog.init(0, null); @@ -462,7 +562,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mCsdWarningDialogFactory, devicePostureController, mTestableLooper.getLooper(), - mDumpManager + mDumpManager, + mFeatureFlags ); dialog.init(0, null); @@ -503,7 +604,9 @@ public class VolumeDialogImplTest extends SysuiTestCase { mCsdWarningDialogFactory, mPostureController, mTestableLooper.getLooper(), - mDumpManager); + mDumpManager, + mFeatureFlags + ); dialog.init(0, null); verify(mPostureController, never()).removeCallback(any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt index 6fc36b08250b..fe5024fdc0a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -16,9 +16,11 @@ package com.android.systemui.wallpapers.data.repository +import android.app.WallpaperInfo import kotlinx.coroutines.flow.MutableStateFlow /** Fake implementation of the wallpaper repository. */ class FakeWallpaperRepository : WallpaperRepository { + override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null) override val wallpaperSupportsAmbientMode = MutableStateFlow(false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt index 132b9b4a02e1..f8b096a7579b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt @@ -65,6 +65,171 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { } @Test + fun wallpaperInfo_nullInfo() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperInfo) + + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(null) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + assertThat(latest).isNull() + } + + @Test + fun wallpaperInfo_hasInfoFromManager() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperInfo) + + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + assertThat(latest).isEqualTo(UNSUPPORTED_WP) + } + + @Test + fun wallpaperInfo_initialValueIsFetched() = + testScope.runTest { + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) + .thenReturn(SUPPORTED_WP) + userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP)) + userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) + + // WHEN the repo initially starts up (underTest is lazy), then it fetches the current + // value for the wallpaper + assertThat(underTest.wallpaperInfo.value).isEqualTo(SUPPORTED_WP) + } + + @Test + fun wallpaperInfo_updatesOnUserChanged() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperInfo) + + val user3 = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0) + val user3Wp = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(user3.id)).thenReturn(user3Wp) + + val user4 = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0) + val user4Wp = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(user4.id)).thenReturn(user4Wp) + + userRepository.setUserInfos(listOf(user3, user4)) + + // WHEN user3 is selected + userRepository.setSelectedUserInfo(user3) + + // THEN user3's wallpaper is used + assertThat(latest).isEqualTo(user3Wp) + + // WHEN the user is switched to user4 + userRepository.setSelectedUserInfo(user4) + + // THEN user4's wallpaper is used + assertThat(latest).isEqualTo(user4Wp) + } + + @Test + fun wallpaperInfo_doesNotUpdateOnUserChanging() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperInfo) + + val user3 = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0) + val user3Wp = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(user3.id)).thenReturn(user3Wp) + + val user4 = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0) + val user4Wp = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(user4.id)).thenReturn(user4Wp) + + userRepository.setUserInfos(listOf(user3, user4)) + + // WHEN user3 is selected + userRepository.setSelectedUserInfo(user3) + + // THEN user3's wallpaper is used + assertThat(latest).isEqualTo(user3Wp) + + // WHEN the user has started switching to user4 but hasn't finished yet + userRepository.selectedUser.value = + SelectedUserModel(user4, SelectionStatus.SELECTION_IN_PROGRESS) + + // THEN the wallpaper still matches user3 + assertThat(latest).isEqualTo(user3Wp) + } + + @Test + fun wallpaperInfo_updatesOnIntent() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperInfo) + + val wp1 = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1) + + assertThat(latest).isEqualTo(wp1) + + // WHEN the info is new and a broadcast is sent + val wp2 = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp2) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + // THEN the flow updates + assertThat(latest).isEqualTo(wp2) + } + + @Test + fun wallpaperInfo_wallpaperNotSupported_alwaysNull() = + testScope.runTest { + whenever(wallpaperManager.isWallpaperSupported).thenReturn(false) + + val latest by collectLastValue(underTest.wallpaperInfo) + assertThat(latest).isNull() + + // Even WHEN there *is* current wallpaper + val wp1 = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + // THEN the value is still null because wallpaper isn't supported + assertThat(latest).isNull() + } + + @Test + fun wallpaperInfo_deviceDoesNotSupportAmbientWallpaper_alwaysFalse() = + testScope.runTest { + context.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_dozeSupportsAodWallpaper, + false + ) + + val latest by collectLastValue(underTest.wallpaperInfo) + assertThat(latest).isNull() + + // Even WHEN there *is* current wallpaper + val wp1 = mock<WallpaperInfo>() + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + // THEN the value is still null because wallpaper isn't supported + assertThat(latest).isNull() + } + + @Test fun wallpaperSupportsAmbientMode_nullInfo_false() = testScope.runTest { val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) @@ -190,14 +355,12 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { testScope.runTest { val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - val info: WallpaperInfo = mock() - whenever(info.supportsAmbientMode()).thenReturn(false) - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(info) + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP) assertThat(latest).isFalse() // WHEN the info now supports ambient mode and a broadcast is sent - whenever(info.supportsAmbientMode()).thenReturn(true) + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( context, Intent(Intent.ACTION_WALLPAPER_CHANGED), 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 4839eeba2124..17bb73b94ac2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -92,7 +92,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -305,6 +305,7 @@ public class BubblesTest extends SysuiTestCase { private TestableLooper mTestableLooper; private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext); + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); private UserHandle mUser0; @@ -423,7 +424,7 @@ public class BubblesTest extends SysuiTestCase { mCommonNotifCollection, mNotifPipeline, mSysUiState, - mock(FeatureFlags.class), + mFeatureFlags, mNotifPipelineFlags, syncExecutor); mBubblesManager.addNotifCallback(mNotifCallback); @@ -432,7 +433,8 @@ public class BubblesTest extends SysuiTestCase { mNotificationTestHelper = new NotificationTestHelper( mContext, mDependency, - TestableLooper.get(this)); + TestableLooper.get(this), + mFeatureFlags); mRow = mNotificationTestHelper.createBubble(mDeleteIntent); mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent); mNonBubbleNotifRow = mNotificationTestHelper.createRow(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index 28892baec3c5..c2e1ac70af80 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -31,9 +31,6 @@ class FakeAuthenticationRepository( private val currentTime: () -> Long, ) : AuthenticationRepository { - private val _isBypassEnabled = MutableStateFlow(false) - override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled - private val _isAutoConfirmEnabled = MutableStateFlow(false) override val isAutoConfirmEnabled: StateFlow<Boolean> = _isAutoConfirmEnabled.asStateFlow() @@ -85,10 +82,6 @@ class FakeAuthenticationRepository( return (credentialOverride ?: DEFAULT_PIN).size } - override fun setBypassEnabled(isBypassEnabled: Boolean) { - _isBypassEnabled.value = isBypassEnabled - } - override suspend fun getFailedAuthenticationAttemptCount(): Int { return failedAttemptCount } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt index b94f816e1ca4..36fa7e65d8ec 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt @@ -62,6 +62,32 @@ class FakeFeatureFlags : FeatureFlags { } } + /** + * Set the given flag's default value if no other value has been set. + * + * REMINDER: You should always test your code with your flag in both configurations, so + * generally you should be setting a particular value. This method should be reserved for + * situations where the flag needs to be read (e.g. in the class constructor), but its + * value shouldn't affect the actual test cases. In those cases, it's mildly safer to use + * this method than to hard-code `false` or `true` because then at least if you're wrong, + * and the flag value *does* matter, you'll notice when the flag is flipped and tests + * start failing. + */ + fun setDefault(flag: BooleanFlag) = booleanFlags.putIfAbsent(flag.id, flag.default) + + /** + * Set the given flag's default value if no other value has been set. + * + * REMINDER: You should always test your code with your flag in both configurations, so + * generally you should be setting a particular value. This method should be reserved for + * situations where the flag needs to be read (e.g. in the class constructor), but its + * value shouldn't affect the actual test cases. In those cases, it's mildly safer to use + * this method than to hard-code `false` or `true` because then at least if you're wrong, + * and the flag value *does* matter, you'll notice when the flag is flipped and tests + * start failing. + */ + fun setDefault(flag: SysPropBooleanFlag) = booleanFlags.putIfAbsent(flag.id, flag.default) + private fun notifyFlagChanged(flag: Flag<*>) { flagListeners[flag.id]?.let { listeners -> listeners.forEach { listener -> diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt index 2715aaa82253..548169e6cccd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt @@ -17,8 +17,8 @@ package com.android.systemui.keyguard.data.repository import com.android.keyguard.FaceAuthUiEvent -import com.android.systemui.keyguard.shared.model.AuthenticationStatus -import com.android.systemui.keyguard.shared.model.DetectionStatus +import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FaceDetectionStatus import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -29,16 +29,16 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository { override val isAuthenticated = MutableStateFlow(false) override val canRunFaceAuth = MutableStateFlow(false) - private val _authenticationStatus = MutableStateFlow<AuthenticationStatus?>(null) - override val authenticationStatus: Flow<AuthenticationStatus> = + private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null) + override val authenticationStatus: Flow<FaceAuthenticationStatus> = _authenticationStatus.filterNotNull() - fun setAuthenticationStatus(status: AuthenticationStatus) { + fun setAuthenticationStatus(status: FaceAuthenticationStatus) { _authenticationStatus.value = status } - private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null) - override val detectionStatus: Flow<DetectionStatus> + private val _detectionStatus = MutableStateFlow<FaceDetectionStatus?>(null) + override val detectionStatus: Flow<FaceDetectionStatus> get() = _detectionStatus.filterNotNull() - fun setDetectionStatus(status: DetectionStatus) { + fun setDetectionStatus(status: FaceDetectionStatus) { _detectionStatus.value = status } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt index 4bfd3d64c98e..38791caf5bfc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt @@ -17,32 +17,38 @@ package com.android.systemui.keyguard.data.repository +import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.filterNotNull class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository { private val _isLockedOut = MutableStateFlow(false) override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow() - - private val _isRunning = MutableStateFlow(false) - override val isRunning: Flow<Boolean> - get() = _isRunning - - private var fpSensorType = MutableStateFlow<BiometricType?>(null) - override val availableFpSensorType: Flow<BiometricType?> - get() = fpSensorType - fun setLockedOut(lockedOut: Boolean) { _isLockedOut.value = lockedOut } + private val _isRunning = MutableStateFlow(false) + override val isRunning: Flow<Boolean> + get() = _isRunning fun setIsRunning(value: Boolean) { _isRunning.value = value } + private var fpSensorType = MutableStateFlow<BiometricType?>(null) + override val availableFpSensorType: Flow<BiometricType?> + get() = fpSensorType fun setAvailableFpSensorType(value: BiometricType?) { fpSensorType.value = value } + + private var _authenticationStatus = MutableStateFlow<FingerprintAuthenticationStatus?>(null) + override val authenticationStatus: Flow<FingerprintAuthenticationStatus> + get() = _authenticationStatus.filterNotNull() + fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) { + _authenticationStatus.value = status + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt index 63097401bc5a..8428566270de 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt @@ -22,11 +22,14 @@ import com.android.systemui.common.shared.model.Position import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.shared.model.ScreenModel +import com.android.systemui.keyguard.shared.model.ScreenState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -56,6 +59,9 @@ class FakeKeyguardRepository : KeyguardRepository { private val _isDozing = MutableStateFlow(false) override val isDozing: StateFlow<Boolean> = _isDozing + private val _dozeTimeTick = MutableSharedFlow<Unit>() + override val dozeTimeTick = _dozeTimeTick + private val _lastDozeTapToWakePosition = MutableStateFlow<Point?>(null) override val lastDozeTapToWakePosition = _lastDozeTapToWakePosition.asStateFlow() @@ -86,6 +92,9 @@ class FakeKeyguardRepository : KeyguardRepository { ) override val wakefulness = _wakefulnessModel + private val _screenModel = MutableStateFlow(ScreenModel(ScreenState.SCREEN_OFF)) + override val screenModel = _screenModel + private val _isUdfpsSupported = MutableStateFlow(false) private val _isKeyguardGoingAway = MutableStateFlow(false) @@ -114,6 +123,11 @@ class FakeKeyguardRepository : KeyguardRepository { return _isKeyguardShowing.value } + private var _isBypassEnabled = false + override fun isBypassEnabled(): Boolean { + return _isBypassEnabled + } + override fun setAnimateDozingTransitions(animate: Boolean) { _animateBottomAreaDozingTransitions.tryEmit(animate) } @@ -142,6 +156,10 @@ class FakeKeyguardRepository : KeyguardRepository { _isDozing.value = isDozing } + override fun dozeTimeTick() { + _dozeTimeTick.tryEmit(Unit) + } + override fun setLastDozeTapToWakePosition(position: Point) { _lastDozeTapToWakePosition.value = position } @@ -198,6 +216,10 @@ class FakeKeyguardRepository : KeyguardRepository { _isKeyguardUnlocked.value = isUnlocked } + fun setBypassEnabled(isEnabled: Boolean) { + _isBypassEnabled = isEnabled + } + override fun isUdfpsSupported(): Boolean { return _isUdfpsSupported.value } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt index 47e1daf4008c..931798130499 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt @@ -142,6 +142,7 @@ class SceneTestUtils( repository = repository, backgroundDispatcher = testDispatcher, userRepository = userRepository, + keyguardRepository = keyguardRepository, clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } } ) } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c1239d53058c..7d46c0cd075f 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -256,7 +256,7 @@ import java.util.function.Predicate; public final class ActiveServices { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM; private static final String TAG_MU = TAG + POSTFIX_MU; - private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; + static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING; private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE; @@ -850,8 +850,7 @@ public final class ActiveServices { // Service.startForeground()), at that point we will consult the BFSL check and the timeout // and make the necessary decisions. setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId, - backgroundStartPrivileges, false /* isBindService */, - !fgRequired /* isStartService */); + backgroundStartPrivileges, false /* isBindService */); if (!mAm.mUserController.exists(r.userId)) { Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId); @@ -894,7 +893,7 @@ public final class ActiveServices { if (fgRequired) { logFgsBackgroundStart(r); - if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) { + if (!r.isFgsAllowedStart() && isBgFgsRestrictionEnabled(r)) { String msg = "startForegroundService() not allowed due to " + "mAllowStartForeground false: service " + r.shortInstanceName; @@ -1060,7 +1059,7 @@ public final class ActiveServices { // Use that as a shortcut if possible to avoid having to recheck all the conditions. final boolean whileInUseAllowsUiJobScheduling = ActivityManagerService.doesReasonCodeAllowSchedulingUserInitiatedJobs( - r.mAllowWhileInUsePermissionInFgsReason); + r.getFgsAllowWIU()); r.updateAllowUiJobScheduling(whileInUseAllowsUiJobScheduling || mAm.canScheduleUserInitiatedJobs(callingUid, callingPid, callingPackage)); } else { @@ -2178,12 +2177,12 @@ public final class ActiveServices { // on a SHORT_SERVICE FGS. // See if the app could start an FGS or not. - r.mAllowStartForeground = REASON_DENIED; + r.clearFgsAllowStart(); setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, - false /* isBindService */, false /* isStartService */); - if (r.mAllowStartForeground == REASON_DENIED) { + false /* isBindService */); + if (!r.isFgsAllowedStart()) { Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + " BFSL DENIED."); } else { @@ -2191,13 +2190,13 @@ public final class ActiveServices { Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + " BFSL Allowed: " + PowerExemptionManager.reasonCodeToString( - r.mAllowStartForeground)); + r.getFgsAllowStart())); } } final boolean fgsStartAllowed = !isBgFgsRestrictionEnabledForService - || (r.mAllowStartForeground != REASON_DENIED); + || r.isFgsAllowedStart(); if (fgsStartAllowed) { if (isNewTypeShortFgs) { @@ -2246,7 +2245,7 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, - false /* isBindService */, false /* isStartService */); + false /* isBindService */); final String temp = "startForegroundDelayMs:" + delayMs; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; @@ -2266,20 +2265,21 @@ public final class ActiveServices { setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, - false /* isBindService */, false /* isStartService */); + false /* isBindService */); } // If the foreground service is not started from TOP process, do not allow it to // have while-in-use location/camera/microphone access. - if (!r.mAllowWhileInUsePermissionInFgs) { + if (!r.isFgsAllowedWIU()) { Slog.w(TAG, "Foreground service started from background can not have " + "location/camera/microphone access: service " + r.shortInstanceName); } + r.maybeLogFgsLogicChange(); if (!bypassBfslCheck) { logFgsBackgroundStart(r); - if (r.mAllowStartForeground == REASON_DENIED + if (!r.isFgsAllowedStart() && isBgFgsRestrictionEnabledForService) { final String msg = "Service.startForeground() not allowed due to " + "mAllowStartForeground false: service " @@ -2378,9 +2378,9 @@ public final class ActiveServices { // The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could // be deferred, make a copy of mAllowStartForeground and // mAllowWhileInUsePermissionInFgs. - r.mAllowStartForegroundAtEntering = r.mAllowStartForeground; + r.mAllowStartForegroundAtEntering = r.getFgsAllowStart(); r.mAllowWhileInUsePermissionInFgsAtEntering = - r.mAllowWhileInUsePermissionInFgs; + r.isFgsAllowedWIU(); r.mStartForegroundCount++; r.mFgsEnterTime = SystemClock.uptimeMillis(); if (!stopProcStatsOp) { @@ -2558,7 +2558,7 @@ public final class ActiveServices { policy.getForegroundServiceTypePolicyInfo(type, defaultToType); final @ForegroundServicePolicyCheckCode int code = policy.checkForegroundServiceTypePolicy( mAm.mContext, r.packageName, r.app.uid, r.app.getPid(), - r.mAllowWhileInUsePermissionInFgs, policyInfo); + r.isFgsAllowedWIU(), policyInfo); RuntimeException exception = null; switch (code) { case FGS_TYPE_POLICY_CHECK_DEPRECATED: { @@ -3701,9 +3701,7 @@ public final class ActiveServices { } clientPsr.addConnection(c); c.startAssociationIfNeeded(); - // Don't set hasAboveClient if binding to self to prevent modifyRawOomAdj() from - // dropping the process' adjustment level. - if (b.client != s.app && c.hasFlag(Context.BIND_ABOVE_CLIENT)) { + if (c.hasFlag(Context.BIND_ABOVE_CLIENT)) { clientPsr.setHasAboveClient(true); } if (c.hasFlag(BIND_ALLOW_WHITELIST_MANAGEMENT)) { @@ -3744,8 +3742,7 @@ public final class ActiveServices { } } setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId, - BackgroundStartPrivileges.NONE, true /* isBindService */, - false /* isStartService */); + BackgroundStartPrivileges.NONE, true /* isBindService */); if (s.app != null) { ProcessServiceRecord servicePsr = s.app.mServices; @@ -7443,54 +7440,80 @@ public final class ActiveServices { * @param callingUid caller app's uid. * @param intent intent to start/bind service. * @param r the service to start. - * @param isStartService True if it's called from Context.startService(). - * False if it's called from Context.startForegroundService() or - * Service.startForeground(). + * @param isBindService True if it's called from bindService(). * @return true if allow, false otherwise. */ private void setFgsRestrictionLocked(String callingPackage, int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, - BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, - boolean isStartService) { + BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { + + @ReasonCode int allowWIU; + @ReasonCode int allowStart; + + // If called from bindService(), do not update the actual fields, but instead + // keep it in a separate set of fields. + if (isBindService) { + allowWIU = r.mAllowWIUInBindService; + allowStart = r.mAllowStartInBindService; + } else { + allowWIU = r.mAllowWhileInUsePermissionInFgsReasonNoBinding; + allowStart = r.mAllowStartForegroundNoBinding; + } + // Check DeviceConfig flag. if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { - if (!r.mAllowWhileInUsePermissionInFgs) { + if (allowWIU == REASON_DENIED) { // BGFGS start restrictions are disabled. We're allowing while-in-use permissions. // Note REASON_OTHER since there's no other suitable reason. - r.mAllowWhileInUsePermissionInFgsReason = REASON_OTHER; + allowWIU = REASON_OTHER; } - r.mAllowWhileInUsePermissionInFgs = true; } - if (!r.mAllowWhileInUsePermissionInFgs - || (r.mAllowStartForeground == REASON_DENIED)) { + if ((allowWIU == REASON_DENIED) + || (allowStart == REASON_DENIED)) { @ReasonCode final int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked( callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges); // We store them to compare the old and new while-in-use logics to each other. // (They're not used for any other purposes.) - if (!r.mAllowWhileInUsePermissionInFgs) { - r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED); - r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse; + if (allowWIU == REASON_DENIED) { + allowWIU = allowWhileInUse; } - if (r.mAllowStartForeground == REASON_DENIED) { - r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked( + if (allowStart == REASON_DENIED) { + allowStart = shouldAllowFgsStartForegroundWithBindingCheckLocked( allowWhileInUse, callingPackage, callingPid, callingUid, intent, r, backgroundStartPrivileges, isBindService); } } + + if (isBindService) { + r.mAllowWIUInBindService = allowWIU; + r.mAllowStartInBindService = allowStart; + } else { + r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU; + r.mAllowStartForegroundNoBinding = allowStart; + + // Also do a binding client check, unless called from bindService(). + if (r.mAllowWIUByBindings == REASON_DENIED) { + r.mAllowWIUByBindings = + shouldAllowFgsWhileInUsePermissionByBindingsLocked(callingUid); + } + if (r.mAllowStartByBindings == REASON_DENIED) { + r.mAllowStartByBindings = r.mAllowWIUByBindings; + } + } } /** * Reset various while-in-use and BFSL related information. */ void resetFgsRestrictionLocked(ServiceRecord r) { - r.mAllowWhileInUsePermissionInFgs = false; - r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED; - r.mAllowStartForeground = REASON_DENIED; + r.clearFgsAllowWIU(); + r.clearFgsAllowStart(); + r.mInfoAllowStartForeground = null; r.mInfoTempFgsAllowListReason = null; r.mLoggedInfoAllowStartForeground = false; - r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs); + r.updateAllowUiJobScheduling(r.isFgsAllowedWIU()); } boolean canStartForegroundServiceLocked(int callingPid, int callingUid, String callingPackage) { @@ -8062,10 +8085,10 @@ public final class ActiveServices { */ if (!r.mLoggedInfoAllowStartForeground) { final String msg = "Background started FGS: " - + ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ") + + (r.isFgsAllowedStart() ? "Allowed " : "Disallowed ") + r.mInfoAllowStartForeground + (r.isShortFgs() ? " (Called on SHORT_SERVICE)" : ""); - if (r.mAllowStartForeground != REASON_DENIED) { + if (r.isFgsAllowedStart()) { if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName, mAm.mConstants.mFgsStartAllowedLogSampleRate)) { Slog.wtfQuiet(TAG, msg); @@ -8105,8 +8128,8 @@ public final class ActiveServices { allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgsAtEntering; fgsStartReasonCode = r.mAllowStartForegroundAtEntering; } else { - allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgs; - fgsStartReasonCode = r.mAllowStartForeground; + allowWhileInUsePermissionInFgs = r.isFgsAllowedWIU(); + fgsStartReasonCode = r.getFgsAllowStart(); } final int callerTargetSdkVersion = r.mRecentCallerApplicationInfo != null ? r.mRecentCallerApplicationInfo.targetSdkVersion : 0; @@ -8295,8 +8318,7 @@ public final class ActiveServices { r.mFgsEnterTime = SystemClock.uptimeMillis(); r.foregroundServiceType = options.mForegroundServiceTypes; setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId, - BackgroundStartPrivileges.NONE, false /* isBindService */, - false /* isStartService */); + BackgroundStartPrivileges.NONE, false /* isBindService */); final ProcessServiceRecord psr = callerApp.mServices; final boolean newService = psr.startService(r); // updateOomAdj. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7ba720eedfba..81858ee6e2c9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -559,6 +559,10 @@ public class ActivityManagerService extends IActivityManager.Stub // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real. static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + + // How long we wait for a launched process to complete its app startup before we ANR. + static final int BIND_APPLICATION_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + // How long we wait to kill an application zygote, after the last process using // it has gone away. static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000; @@ -1624,6 +1628,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int UPDATE_CACHED_APP_HIGH_WATERMARK = 79; static final int ADD_UID_TO_OBSERVER_MSG = 80; static final int REMOVE_UID_FROM_OBSERVER_MSG = 81; + static final int BIND_APPLICATION_TIMEOUT_MSG = 82; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1976,6 +1981,16 @@ public class ActivityManagerService extends IActivityManager.Stub case UPDATE_CACHED_APP_HIGH_WATERMARK: { mAppProfiler.mCachedAppsWatermarkData.updateCachedAppsSnapshot((long) msg.obj); } break; + case BIND_APPLICATION_TIMEOUT_MSG: { + ProcessRecord app = (ProcessRecord) msg.obj; + + final String anrMessage; + synchronized (app) { + anrMessage = "Process " + app + " failed to complete startup"; + } + + mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage)); + } break; } } } @@ -4734,6 +4749,12 @@ public class ActivityManagerService extends IActivityManager.Stub app.getDisabledCompatChanges(), serializedSystemFontMap, app.getStartElapsedTime(), app.getStartUptime()); } + + Message msg = mHandler.obtainMessage(BIND_APPLICATION_TIMEOUT_MSG); + msg.obj = app; + mHandler.sendMessageDelayed(msg, BIND_APPLICATION_TIMEOUT); + mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); + if (profilerInfo != null) { profilerInfo.closeFd(); profilerInfo = null; @@ -4808,7 +4829,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (app != null && app.getStartUid() == uid && app.getStartSeq() == startSeq) { - mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); + mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_MSG, app); } else { Slog.wtf(TAG, "Mismatched or missing ProcessRecord: " + app + ". Pid: " + pid + ". Uid: " + uid); diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index f420619db490..5d0fefc75a28 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -249,6 +249,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private static final int MSG_CHECK_HEALTH = 5; private static final int MSG_CHECK_PENDING_COLD_START_VALIDITY = 6; private static final int MSG_PROCESS_FREEZABLE_CHANGED = 7; + private static final int MSG_UID_STATE_CHANGED = 8; private void enqueueUpdateRunningList() { mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST); @@ -295,6 +296,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } return true; } + case MSG_UID_STATE_CHANGED: { + final int uid = (int) msg.obj; + final int procState = msg.arg1; + synchronized (mService) { + if (procState == ActivityManager.PROCESS_STATE_TOP) { + mUidForeground.put(uid, true); + } else { + mUidForeground.delete(uid); + } + refreshProcessQueuesLocked(uid); + } + return true; + } } return false; }; @@ -672,7 +686,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @Override public void onProcessFreezableChangedLocked(@NonNull ProcessRecord app) { mLocalHandler.removeMessages(MSG_PROCESS_FREEZABLE_CHANGED, app); - mLocalHandler.sendMessage(mHandler.obtainMessage(MSG_PROCESS_FREEZABLE_CHANGED, app)); + mLocalHandler.obtainMessage(MSG_PROCESS_FREEZABLE_CHANGED, app).sendToTarget(); } @Override @@ -1601,14 +1615,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) { - synchronized (mService) { - if (procState == ActivityManager.PROCESS_STATE_TOP) { - mUidForeground.put(uid, true); - } else { - mUidForeground.delete(uid); - } - refreshProcessQueuesLocked(uid); - } + mLocalHandler.removeMessages(MSG_UID_STATE_CHANGED, uid); + mLocalHandler.obtainMessage(MSG_UID_STATE_CHANGED, procState, 0, uid) + .sendToTarget(); } }, ActivityManager.UID_OBSERVER_PROCSTATE, ActivityManager.PROCESS_STATE_TOP, "android"); diff --git a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java index 38e7371e7075..4f5b5e1fbd68 100644 --- a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java +++ b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java @@ -479,8 +479,8 @@ public class ForegroundServiceTypeLoggerModule { r.appInfo.uid, r.shortInstanceName, fgsState, // FGS State - r.mAllowWhileInUsePermissionInFgs, // allowWhileInUsePermissionInFgs - r.mAllowStartForeground, // fgsStartReasonCode + r.isFgsAllowedWIU(), // allowWhileInUsePermissionInFgs + r.getFgsAllowStart(), // fgsStartReasonCode r.appInfo.targetSdkVersion, r.mRecentCallingUid, 0, // callerTargetSdkVersion diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index a682c85f03b2..459c6ff3504a 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -2222,7 +2222,7 @@ public class OomAdjuster { if (s.isForeground) { final int fgsType = s.foregroundServiceType; - if (s.mAllowWhileInUsePermissionInFgs) { + if (s.isFgsAllowedWIU()) { capabilityFromFGS |= (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0; diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java index 7ff6d116baaf..81d0b6ac700b 100644 --- a/services/core/java/com/android/server/am/ProcessServiceRecord.java +++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java @@ -341,8 +341,7 @@ final class ProcessServiceRecord { mHasAboveClient = false; for (int i = mConnections.size() - 1; i >= 0; i--) { ConnectionRecord cr = mConnections.valueAt(i); - if (cr.binding.service.app.mServices != this - && cr.hasFlag(Context.BIND_ABOVE_CLIENT)) { + if (cr.hasFlag(Context.BIND_ABOVE_CLIENT)) { mHasAboveClient = true; break; } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 50fe6d71d26e..aabab61c36f4 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -21,9 +21,11 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE; import static android.os.PowerExemptionManager.REASON_DENIED; +import static android.os.PowerExemptionManager.reasonCodeToString; import static android.os.Process.INVALID_UID; import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.server.am.ActiveServices.TAG_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -172,11 +174,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN private BackgroundStartPrivileges mBackgroundStartPrivilegesByStartMerged = BackgroundStartPrivileges.NONE; - // allow while-in-use permissions in foreground service or not. + // Reason code for allow while-in-use permissions in foreground service. + // If it's not DENIED, while-in-use permissions are allowed. // while-in-use permissions in FGS started from background might be restricted. - boolean mAllowWhileInUsePermissionInFgs; @PowerExemptionManager.ReasonCode - int mAllowWhileInUsePermissionInFgsReason = REASON_DENIED; + int mAllowWhileInUsePermissionInFgsReasonNoBinding = REASON_DENIED; // A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state. boolean mAllowWhileInUsePermissionInFgsAtEntering; @@ -205,15 +207,114 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // allow the service becomes foreground service? Service started from background may not be // allowed to become a foreground service. - @PowerExemptionManager.ReasonCode int mAllowStartForeground = REASON_DENIED; + @PowerExemptionManager.ReasonCode + int mAllowStartForegroundNoBinding = REASON_DENIED; // A copy of mAllowStartForeground's value when the service is entering FGS state. - @PowerExemptionManager.ReasonCode int mAllowStartForegroundAtEntering = REASON_DENIED; + @PowerExemptionManager.ReasonCode + int mAllowStartForegroundAtEntering = REASON_DENIED; // Debug info why mAllowStartForeground is allowed or denied. String mInfoAllowStartForeground; // Debug info if mAllowStartForeground is allowed because of a temp-allowlist. ActivityManagerService.FgsTempAllowListItem mInfoTempFgsAllowListReason; // Is the same mInfoAllowStartForeground string has been logged before? Used for dedup. boolean mLoggedInfoAllowStartForeground; + + @PowerExemptionManager.ReasonCode + int mAllowWIUInBindService = REASON_DENIED; + + @PowerExemptionManager.ReasonCode + int mAllowWIUByBindings = REASON_DENIED; + + @PowerExemptionManager.ReasonCode + int mAllowStartInBindService = REASON_DENIED; + + @PowerExemptionManager.ReasonCode + int mAllowStartByBindings = REASON_DENIED; + + @PowerExemptionManager.ReasonCode + int getFgsAllowWIU() { + return mAllowWhileInUsePermissionInFgsReasonNoBinding != REASON_DENIED + ? mAllowWhileInUsePermissionInFgsReasonNoBinding + : mAllowWIUInBindService; + } + + boolean isFgsAllowedWIU() { + return getFgsAllowWIU() != REASON_DENIED; + } + + @PowerExemptionManager.ReasonCode + int getFgsAllowStart() { + return mAllowStartForegroundNoBinding != REASON_DENIED + ? mAllowStartForegroundNoBinding + : mAllowStartInBindService; + } + + boolean isFgsAllowedStart() { + return getFgsAllowStart() != REASON_DENIED; + } + + void clearFgsAllowWIU() { + mAllowWhileInUsePermissionInFgsReasonNoBinding = REASON_DENIED; + mAllowWIUInBindService = REASON_DENIED; + mAllowWIUByBindings = REASON_DENIED; + } + + void clearFgsAllowStart() { + mAllowStartForegroundNoBinding = REASON_DENIED; + mAllowStartInBindService = REASON_DENIED; + mAllowStartByBindings = REASON_DENIED; + } + + @PowerExemptionManager.ReasonCode + int reasonOr(@PowerExemptionManager.ReasonCode int first, + @PowerExemptionManager.ReasonCode int second) { + return first != REASON_DENIED ? first : second; + } + + boolean allowedChanged(@PowerExemptionManager.ReasonCode int first, + @PowerExemptionManager.ReasonCode int second) { + return (first == REASON_DENIED) != (second == REASON_DENIED); + } + + String changeMessage(@PowerExemptionManager.ReasonCode int first, + @PowerExemptionManager.ReasonCode int second) { + return reasonOr(first, second) == REASON_DENIED ? "DENIED" + : ("ALLOWED (" + + reasonCodeToString(first) + + "+" + + reasonCodeToString(second) + + ")"); + } + + void maybeLogFgsLogicChange() { + final int origWiu = reasonOr(mAllowWhileInUsePermissionInFgsReasonNoBinding, + mAllowWIUInBindService); + final int newWiu = reasonOr(mAllowWhileInUsePermissionInFgsReasonNoBinding, + mAllowWIUByBindings); + final int origStart = reasonOr(mAllowStartForegroundNoBinding, mAllowStartInBindService); + final int newStart = reasonOr(mAllowStartForegroundNoBinding, mAllowStartByBindings); + + final boolean wiuChanged = allowedChanged(origWiu, newWiu); + final boolean startChanged = allowedChanged(origStart, newStart); + + if (!wiuChanged && !startChanged) { + return; + } + final String message = "FGS logic changed:" + + (wiuChanged ? " [WIU changed]" : "") + + (startChanged ? " [BFSL changed]" : "") + + " OW:" // Orig-WIU + + changeMessage(mAllowWhileInUsePermissionInFgsReasonNoBinding, + mAllowWIUInBindService) + + " NW:" // New-WIU + + changeMessage(mAllowWhileInUsePermissionInFgsReasonNoBinding, mAllowWIUByBindings) + + " OS:" // Orig-start + + changeMessage(mAllowStartForegroundNoBinding, mAllowStartInBindService) + + " NS:" // New-start + + changeMessage(mAllowStartForegroundNoBinding, mAllowStartByBindings); + Slog.wtf(TAG_SERVICE, message); + } + // The number of times Service.startForeground() is called, after this service record is // created. (i.e. due to "bound" or "start".) It never decreases, even when stopForeground() // is called. @@ -502,7 +603,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ProtoUtils.toDuration(proto, ServiceRecordProto.RESTART_TIME, restartTime, now); proto.write(ServiceRecordProto.CREATED_FROM_FG, createdFromFg); proto.write(ServiceRecordProto.ALLOW_WHILE_IN_USE_PERMISSION_IN_FGS, - mAllowWhileInUsePermissionInFgs); + isFgsAllowedWIU()); if (startRequested || delayedStop || lastStartId != 0) { long startToken = proto.start(ServiceRecordProto.START); @@ -618,7 +719,13 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN pw.println(mBackgroundStartPrivilegesByStartMerged); } pw.print(prefix); pw.print("mAllowWhileInUsePermissionInFgsReason="); - pw.println(PowerExemptionManager.reasonCodeToString(mAllowWhileInUsePermissionInFgsReason)); + pw.println(PowerExemptionManager.reasonCodeToString( + mAllowWhileInUsePermissionInFgsReasonNoBinding)); + + pw.print(prefix); pw.print("mAllowWIUInBindService="); + pw.println(PowerExemptionManager.reasonCodeToString(mAllowWIUInBindService)); + pw.print(prefix); pw.print("mAllowWIUByBindings="); + pw.println(PowerExemptionManager.reasonCodeToString(mAllowWIUByBindings)); pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling); pw.print(prefix); pw.print("recentCallingPackage="); @@ -626,7 +733,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN pw.print(prefix); pw.print("recentCallingUid="); pw.println(mRecentCallingUid); pw.print(prefix); pw.print("allowStartForeground="); - pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartForeground)); + pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartForegroundNoBinding)); + pw.print(prefix); pw.print("mAllowStartInBindService="); + pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartInBindService)); + pw.print(prefix); pw.print("mAllowStartByBindings="); + pw.println(PowerExemptionManager.reasonCodeToString(mAllowStartByBindings)); + pw.print(prefix); pw.print("startForegroundCount="); pw.println(mStartForegroundCount); pw.print(prefix); pw.print("infoAllowStartForeground="); diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index e8ffe4feb458..279aaf9d3253 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -17,6 +17,8 @@ package com.android.server.biometrics; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.Authenticators; import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE; @@ -369,7 +371,7 @@ public class BiometricService extends SystemService { public boolean getConfirmationAlwaysRequired(@BiometricAuthenticator.Modality int modality, int userId) { switch (modality) { - case BiometricAuthenticator.TYPE_FACE: + case TYPE_FACE: if (!mFaceAlwaysRequireConfirmation.containsKey(userId)) { onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, @@ -567,22 +569,6 @@ public class BiometricService extends SystemService { Utils.combineAuthenticatorBundles(promptInfo); - // Set the default title if necessary. - if (promptInfo.isUseDefaultTitle()) { - if (TextUtils.isEmpty(promptInfo.getTitle())) { - promptInfo.setTitle(getContext() - .getString(R.string.biometric_dialog_default_title)); - } - } - - // Set the default subtitle if necessary. - if (promptInfo.isUseDefaultSubtitle()) { - if (TextUtils.isEmpty(promptInfo.getSubtitle())) { - promptInfo.setSubtitle(getContext() - .getString(R.string.biometric_dialog_default_subtitle)); - } - } - final long requestId = mRequestCounter.get(); mHandler.post(() -> handleAuthenticate( token, requestId, operationId, userId, receiver, opPackageName, promptInfo)); @@ -1302,6 +1288,33 @@ public class BiometricService extends SystemService { opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(), getContext(), mBiometricCameraManager); + // Set the default title if necessary. + if (promptInfo.isUseDefaultTitle()) { + if (TextUtils.isEmpty(promptInfo.getTitle())) { + promptInfo.setTitle(getContext() + .getString(R.string.biometric_dialog_default_title)); + } + } + + final int eligible = preAuthInfo.getEligibleModalities(); + final boolean hasEligibleFingerprintSensor = + (eligible & TYPE_FINGERPRINT) == TYPE_FINGERPRINT; + final boolean hasEligibleFaceSensor = (eligible & TYPE_FACE) == TYPE_FACE; + + // Set the subtitle according to the modality. + if (promptInfo.isUseDefaultSubtitle()) { + if (hasEligibleFingerprintSensor && hasEligibleFaceSensor) { + promptInfo.setSubtitle(getContext() + .getString(R.string.biometric_dialog_default_subtitle)); + } else if (hasEligibleFingerprintSensor) { + promptInfo.setSubtitle(getContext() + .getString(R.string.biometric_dialog_fingerprint_subtitle)); + } else if (hasEligibleFaceSensor) { + promptInfo.setSubtitle(getContext() + .getString(R.string.biometric_dialog_face_subtitle)); + } + } + final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 0b04159194d1..f8f0088ac047 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -613,16 +613,26 @@ public class CameraServiceProxy extends SystemService @Override public boolean isCameraDisabled(int userId) { - DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); - if (dpm == null) { - Slog.e(TAG, "Failed to get the device policy manager service"); + if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { + Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + + " doesn't match expected camera service UID!"); return false; } + final long ident = Binder.clearCallingIdentity(); try { - return dpm.getCameraDisabled(null, userId); - } catch (Exception e) { - e.printStackTrace(); - return false; + DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + if (dpm == null) { + Slog.e(TAG, "Failed to get the device policy manager service"); + return false; + } + try { + return dpm.getCameraDisabled(null, userId); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } finally { + Binder.restoreCallingIdentity(ident); } } }; diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java index dd5afa2bdc39..da51569ee5cc 100644 --- a/services/core/java/com/android/server/display/DisplayBrightnessState.java +++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java @@ -33,12 +33,15 @@ public final class DisplayBrightnessState { private final String mDisplayBrightnessStrategyName; private final boolean mShouldUseAutoBrightness; + private final boolean mIsSlowChange; + private DisplayBrightnessState(Builder builder) { mBrightness = builder.getBrightness(); mSdrBrightness = builder.getSdrBrightness(); mBrightnessReason = builder.getBrightnessReason(); mDisplayBrightnessStrategyName = builder.getDisplayBrightnessStrategyName(); mShouldUseAutoBrightness = builder.getShouldUseAutoBrightness(); + mIsSlowChange = builder.isSlowChange(); } /** @@ -77,6 +80,13 @@ public final class DisplayBrightnessState { return mShouldUseAutoBrightness; } + /** + * @return {@code true} if the should transit to new state slowly + */ + public boolean isSlowChange() { + return mIsSlowChange; + } + @Override public String toString() { StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:"); @@ -88,6 +98,8 @@ public final class DisplayBrightnessState { stringBuilder.append(getBrightnessReason()); stringBuilder.append("\n shouldUseAutoBrightness:"); stringBuilder.append(getShouldUseAutoBrightness()); + stringBuilder.append("\n isSlowChange:"); + stringBuilder.append(mIsSlowChange); return stringBuilder.toString(); } @@ -111,13 +123,14 @@ public final class DisplayBrightnessState { && mBrightnessReason.equals(otherState.getBrightnessReason()) && TextUtils.equals(mDisplayBrightnessStrategyName, otherState.getDisplayBrightnessStrategyName()) - && mShouldUseAutoBrightness == otherState.getShouldUseAutoBrightness(); + && mShouldUseAutoBrightness == otherState.getShouldUseAutoBrightness() + && mIsSlowChange == otherState.isSlowChange(); } @Override public int hashCode() { - return Objects.hash( - mBrightness, mSdrBrightness, mBrightnessReason, mShouldUseAutoBrightness); + return Objects.hash(mBrightness, mSdrBrightness, mBrightnessReason, + mShouldUseAutoBrightness, mIsSlowChange); } /** @@ -129,6 +142,7 @@ public final class DisplayBrightnessState { private BrightnessReason mBrightnessReason = new BrightnessReason(); private String mDisplayBrightnessStrategyName; private boolean mShouldUseAutoBrightness; + private boolean mIsSlowChange; /** * Create a builder starting with the values from the specified {@link @@ -143,6 +157,7 @@ public final class DisplayBrightnessState { builder.setBrightnessReason(state.getBrightnessReason()); builder.setDisplayBrightnessStrategyName(state.getDisplayBrightnessStrategyName()); builder.setShouldUseAutoBrightness(state.getShouldUseAutoBrightness()); + builder.setIsSlowChange(state.isSlowChange()); return builder; } @@ -237,6 +252,21 @@ public final class DisplayBrightnessState { } /** + * See {@link DisplayBrightnessState#isSlowChange()}. + */ + public Builder setIsSlowChange(boolean shouldUseAutoBrightness) { + this.mIsSlowChange = shouldUseAutoBrightness; + return this; + } + + /** + * See {@link DisplayBrightnessState#isSlowChange()}. + */ + public boolean isSlowChange() { + return mIsSlowChange; + } + + /** * This is used to construct an immutable DisplayBrightnessState object from its builder */ public DisplayBrightnessState build() { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index ffecf2b7018d..c5d0c177a46d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -141,6 +141,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int MSG_STATSD_HBM_BRIGHTNESS = 13; private static final int MSG_SWITCH_USER = 14; private static final int MSG_BOOT_COMPLETED = 15; + private static final int MSG_SET_DWBC_STRONG_MODE = 16; + private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 17; + private static final int MSG_SET_DWBC_LOGGING_ENABLED = 18; private static final int PROXIMITY_UNKNOWN = -1; private static final int PROXIMITY_NEGATIVE = 0; @@ -436,6 +439,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private final boolean mSkipScreenOnBrightnessRamp; // Display white balance components. + // Critical methods must be called on DPC handler thread. @Nullable private final DisplayWhiteBalanceSettings mDisplayWhiteBalanceSettings; @Nullable @@ -680,9 +684,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call DisplayWhiteBalanceController displayWhiteBalanceController = null; if (mDisplayId == Display.DEFAULT_DISPLAY) { try { + displayWhiteBalanceController = injector.getDisplayWhiteBalanceController( + mHandler, mSensorManager, resources); displayWhiteBalanceSettings = new DisplayWhiteBalanceSettings(mContext, mHandler); - displayWhiteBalanceController = DisplayWhiteBalanceFactory.create(mHandler, - mSensorManager, resources); displayWhiteBalanceSettings.setCallbacks(this); displayWhiteBalanceController.setCallbacks(this); } catch (Exception e) { @@ -1025,10 +1029,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call Message msg = mHandler.obtainMessage(MSG_STOP); mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setEnabled(false); - } - if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.stop(); } @@ -1334,9 +1334,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.switchToInteractiveScreenBrightnessMode(); } } - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setStrongModeEnabled(isIdle); - } + + Message msg = mHandler.obtainMessage(); + msg.what = MSG_SET_DWBC_STRONG_MODE; + msg.arg1 = isIdle ? 1 : 0; + mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @@ -1405,8 +1407,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mScreenOffBrightnessSensorController != null) { mScreenOffBrightnessSensorController.stop(); } + + if (mDisplayWhiteBalanceController != null) { + mDisplayWhiteBalanceController.setEnabled(false); + } } + // Call from handler thread private void updatePowerState() { Trace.traceBegin(Trace.TRACE_TAG_POWER, "DisplayPowerController#updatePowerState"); @@ -2058,6 +2065,32 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } + private void setDwbcOverride(float cct) { + if (mDisplayWhiteBalanceController != null) { + mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct); + // The ambient color temperature override is only applied when the ambient color + // temperature changes or is updated, so it doesn't necessarily change the screen color + // temperature immediately. So, let's make it! + // We can call this directly, since we're already on the handler thread. + updatePowerState(); + } + } + + private void setDwbcStrongMode(int arg) { + if (mDisplayWhiteBalanceController != null) { + final boolean isIdle = (arg == 1); + mDisplayWhiteBalanceController.setStrongModeEnabled(isIdle); + } + } + + private void setDwbcLoggingEnabled(int arg) { + if (mDisplayWhiteBalanceController != null) { + final boolean shouldEnable = (arg == 1); + mDisplayWhiteBalanceController.setLoggingEnabled(shouldEnable); + mDisplayWhiteBalanceSettings.setLoggingEnabled(shouldEnable); + } + } + @Override public void updateBrightness() { sendUpdatePowerState(); @@ -3331,6 +3364,19 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBootCompleted = true; updatePowerState(); break; + + case MSG_SET_DWBC_STRONG_MODE: + setDwbcStrongMode(msg.arg1); + break; + + case MSG_SET_DWBC_COLOR_OVERRIDE: + final float cct = Float.intBitsToFloat(msg.arg1); + setDwbcOverride(cct); + break; + + case MSG_SET_DWBC_LOGGING_ENABLED: + setDwbcLoggingEnabled(msg.arg1); + break; } } } @@ -3398,21 +3444,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) { - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setLoggingEnabled(enabled); - mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled); - } + Message msg = mHandler.obtainMessage(); + msg.what = MSG_SET_DWBC_LOGGING_ENABLED; + msg.arg1 = enabled ? 1 : 0; + msg.sendToTarget(); } @Override public void setAmbientColorTemperatureOverride(float cct) { - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct); - // The ambient color temperature override is only applied when the ambient color - // temperature changes or is updated, so it doesn't necessarily change the screen color - // temperature immediately. So, let's make it! - sendUpdatePowerState(); - } + Message msg = mHandler.obtainMessage(); + msg.what = MSG_SET_DWBC_COLOR_OVERRIDE; + msg.arg1 = Float.floatToIntBits(cct); + msg.sendToTarget(); } @VisibleForTesting @@ -3543,6 +3586,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, hbmMetadata, context); } + + DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, + SensorManager sensorManager, Resources resources) { + return DisplayWhiteBalanceFactory.create(handler, + sensorManager, resources); + } } static class CachedBrightnessInfo { diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 7417aeb22a64..029616cef95e 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -142,6 +142,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private static final int MSG_STATSD_HBM_BRIGHTNESS = 11; private static final int MSG_SWITCH_USER = 12; private static final int MSG_BOOT_COMPLETED = 13; + private static final int MSG_SET_DWBC_STRONG_MODE = 14; + private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 15; + private static final int MSG_SET_DWBC_LOGGING_ENABLED = 16; private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500; @@ -368,6 +371,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private final boolean mSkipScreenOnBrightnessRamp; // Display white balance components. + // Critical methods must be called on DPC2 handler thread. @Nullable private final DisplayWhiteBalanceSettings mDisplayWhiteBalanceSettings; @Nullable @@ -438,9 +442,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal @Nullable private BrightnessMappingStrategy mIdleModeBrightnessMapper; - // Indicates whether we should ramp slowly to the brightness value to follow. - private boolean mBrightnessToFollowSlowChange; - private boolean mIsRbcActive; // Animators. @@ -572,9 +573,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal DisplayWhiteBalanceController displayWhiteBalanceController = null; if (mDisplayId == Display.DEFAULT_DISPLAY) { try { + displayWhiteBalanceController = mInjector.getDisplayWhiteBalanceController( + mHandler, mSensorManager, resources); displayWhiteBalanceSettings = new DisplayWhiteBalanceSettings(mContext, mHandler); - displayWhiteBalanceController = DisplayWhiteBalanceFactory.create(mHandler, - mSensorManager, resources); displayWhiteBalanceSettings.setCallbacks(this); displayWhiteBalanceController.setCallbacks(this); } catch (Exception e) { @@ -850,10 +851,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal Message msg = mHandler.obtainMessage(MSG_STOP); mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setEnabled(false); - } - if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.stop(); } @@ -1164,9 +1161,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mAutomaticBrightnessController.switchToInteractiveScreenBrightnessMode(); } } - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setStrongModeEnabled(isIdle); - } + Message msg = mHandler.obtainMessage(); + msg.what = MSG_SET_DWBC_STRONG_MODE; + msg.arg1 = isIdle ? 1 : 0; + mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @@ -1221,8 +1219,13 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal if (mScreenOffBrightnessSensorController != null) { mScreenOffBrightnessSensorController.stop(); } + + if (mDisplayWhiteBalanceController != null) { + mDisplayWhiteBalanceController.setEnabled(false); + } } + // Call from handler thread private void updatePowerState() { Trace.traceBegin(Trace.TRACE_TAG_POWER, "DisplayPowerController#updatePowerState"); @@ -1283,7 +1286,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // actual state instead of the desired one. animateScreenStateChange(state, mDisplayStateController.shouldPerformScreenOffTransition()); state = mPowerState.getScreenState(); - boolean slowChange = false; + final boolean userSetBrightnessChanged = mDisplayBrightnessController .updateUserSetScreenBrightness(); @@ -1292,11 +1295,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal float brightnessState = displayBrightnessState.getBrightness(); float rawBrightnessState = displayBrightnessState.getBrightness(); mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason()); - - if (displayBrightnessState.getBrightnessReason().getReason() - == BrightnessReason.REASON_FOLLOWER) { - slowChange = mBrightnessToFollowSlowChange; - } + boolean slowChange = displayBrightnessState.isSlowChange(); // Set up the ScreenOff controller used when coming out of SCREEN_OFF and the ALS sensor // doesn't yet have a valid lux value to use with auto-brightness. @@ -1346,6 +1345,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal .getRawAutomaticScreenBrightness(); brightnessState = clampScreenBrightness(brightnessState); // slowly adapt to auto-brightness + // TODO(b/253226419): slowChange should be decided by strategy.updateBrightness slowChange = mAutomaticBrightnessStrategy.hasAppliedAutoBrightness() && !mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged(); brightnessAdjustmentFlags = @@ -1726,6 +1726,32 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } } + private void setDwbcOverride(float cct) { + if (mDisplayWhiteBalanceController != null) { + mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct); + // The ambient color temperature override is only applied when the ambient color + // temperature changes or is updated, so it doesn't necessarily change the screen color + // temperature immediately. So, let's make it! + // We can call this directly, since we're already on the handler thread. + updatePowerState(); + } + } + + private void setDwbcStrongMode(int arg) { + if (mDisplayWhiteBalanceController != null) { + final boolean isIdle = (arg == 1); + mDisplayWhiteBalanceController.setStrongModeEnabled(isIdle); + } + } + + private void setDwbcLoggingEnabled(int arg) { + if (mDisplayWhiteBalanceController != null) { + final boolean enabled = (arg == 1); + mDisplayWhiteBalanceController.setLoggingEnabled(enabled); + mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled); + } + } + @Override public void updateBrightness() { sendUpdatePowerState(); @@ -2224,17 +2250,17 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal boolean slowChange) { mBrightnessRangeController.onAmbientLuxChange(ambientLux); if (nits < 0) { - mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness); + mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, slowChange); } else { float brightness = mDisplayBrightnessController.convertToFloatScale(nits); if (BrightnessUtils.isValidBrightnessValue(brightness)) { - mDisplayBrightnessController.setBrightnessToFollow(brightness); + mDisplayBrightnessController.setBrightnessToFollow(brightness, slowChange); } else { // The device does not support nits - mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness); + mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, + slowChange); } } - mBrightnessToFollowSlowChange = slowChange; sendUpdatePowerState(); } @@ -2374,7 +2400,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal pw.println(" mReportedToPolicy=" + reportedToPolicyToString(mReportedScreenStateToPolicy)); pw.println(" mIsRbcActive=" + mIsRbcActive); - pw.println(" mBrightnessToFollowSlowChange=" + mBrightnessToFollowSlowChange); IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); mAutomaticBrightnessStrategy.dump(ipw); @@ -2755,6 +2780,19 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mBootCompleted = true; updatePowerState(); break; + + case MSG_SET_DWBC_STRONG_MODE: + setDwbcStrongMode(msg.arg1); + break; + + case MSG_SET_DWBC_COLOR_OVERRIDE: + final float cct = Float.intBitsToFloat(msg.arg1); + setDwbcOverride(cct); + break; + + case MSG_SET_DWBC_LOGGING_ENABLED: + setDwbcLoggingEnabled(msg.arg1); + break; } } } @@ -2805,21 +2843,18 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal @Override public void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) { - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setLoggingEnabled(enabled); - mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled); - } + Message msg = mHandler.obtainMessage(); + msg.what = MSG_SET_DWBC_LOGGING_ENABLED; + msg.arg1 = enabled ? 1 : 0; + msg.sendToTarget(); } @Override public void setAmbientColorTemperatureOverride(float cct) { - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct); - // The ambient color temperature override is only applied when the ambient color - // temperature changes or is updated, so it doesn't necessarily change the screen color - // temperature immediately. So, let's make it! - sendUpdatePowerState(); - } + Message msg = mHandler.obtainMessage(); + msg.what = MSG_SET_DWBC_COLOR_OVERRIDE; + msg.arg1 = Float.floatToIntBits(cct); + msg.sendToTarget(); } /** Functional interface for providing time. */ @@ -2946,6 +2981,12 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal boolean isColorFadeEnabled() { return !ActivityManager.isLowRamDeviceStatic(); } + + DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, + SensorManager sensorManager, Resources resources) { + return DisplayWhiteBalanceFactory.create(handler, + sensorManager, resources); + } } static class CachedBrightnessInfo { diff --git a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java index 3fae22434751..8bf675cb33b1 100644 --- a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java +++ b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java @@ -54,6 +54,16 @@ public final class BrightnessUtils { public static DisplayBrightnessState constructDisplayBrightnessState( int brightnessChangeReason, float brightness, float sdrBrightness, String displayBrightnessStrategyName) { + return constructDisplayBrightnessState(brightnessChangeReason, brightness, sdrBrightness, + displayBrightnessStrategyName, /* slowChange= */ false); + } + + /** + * A utility to construct the DisplayBrightnessState + */ + public static DisplayBrightnessState constructDisplayBrightnessState( + int brightnessChangeReason, float brightness, float sdrBrightness, + String displayBrightnessStrategyName, boolean slowChange) { BrightnessReason brightnessReason = new BrightnessReason(); brightnessReason.setReason(brightnessChangeReason); return new DisplayBrightnessState.Builder() @@ -61,6 +71,7 @@ public final class BrightnessUtils { .setSdrBrightness(sdrBrightness) .setBrightnessReason(brightnessReason) .setDisplayBrightnessStrategyName(displayBrightnessStrategyName) + .setIsSlowChange(slowChange) .build(); } } diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java index ffd62a387a64..d6f0098c13cb 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java @@ -164,10 +164,10 @@ public final class DisplayBrightnessController { /** * Sets the brightness to follow */ - public void setBrightnessToFollow(Float brightnessToFollow) { + public void setBrightnessToFollow(float brightnessToFollow, boolean slowChange) { synchronized (mLock) { mDisplayBrightnessStrategySelector.getFollowerDisplayBrightnessStrategy() - .setBrightnessToFollow(brightnessToFollow); + .setBrightnessToFollow(brightnessToFollow, slowChange); } } diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java index 090ec13570cf..585f576c25c3 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java @@ -37,9 +37,13 @@ public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy { // Set to PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no brightness to follow set. private float mBrightnessToFollow; + // Indicates whether we should ramp slowly to the brightness value to follow. + private boolean mBrightnessToFollowSlowChange; + public FollowerBrightnessStrategy(int displayId) { mDisplayId = displayId; mBrightnessToFollow = PowerManager.BRIGHTNESS_INVALID_FLOAT; + mBrightnessToFollowSlowChange = false; } @Override @@ -48,7 +52,7 @@ public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy { // Todo(b/241308599): Introduce a validator class and add validations before setting // the brightness return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_FOLLOWER, - mBrightnessToFollow, mBrightnessToFollow, getName()); + mBrightnessToFollow, mBrightnessToFollow, getName(), mBrightnessToFollowSlowChange); } @Override @@ -60,8 +64,12 @@ public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy { return mBrightnessToFollow; } - public void setBrightnessToFollow(float brightnessToFollow) { + /** + * Updates brightness value and brightness slowChange flag + **/ + public void setBrightnessToFollow(float brightnessToFollow, boolean slowChange) { mBrightnessToFollow = brightnessToFollow; + mBrightnessToFollowSlowChange = slowChange; } /** @@ -71,5 +79,6 @@ public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy { writer.println("FollowerBrightnessStrategy:"); writer.println(" mDisplayId=" + mDisplayId); writer.println(" mBrightnessToFollow:" + mBrightnessToFollow); + writer.println(" mBrightnessToFollowSlowChange:" + mBrightnessToFollowSlowChange); } } diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index 5b772fc917c5..4ad26c46d7ed 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -37,8 +37,11 @@ import java.util.Objects; * - Uses the AmbientColorTemperatureSensor to detect changes in the ambient color temperature; * - Uses the AmbientColorTemperatureFilter to average these changes over time, filter out the * noise, and arrive at an estimate of the actual ambient color temperature; - * - Uses the DisplayWhiteBalanceThrottler to decide whether the display color tempearture should + * - Uses the DisplayWhiteBalanceThrottler to decide whether the display color temperature should * be updated, suppressing changes that are too frequent or too minor. + * + * Calls to this class must happen on the DisplayPowerController(2) handler, to ensure + * values do not get out of sync. */ public class DisplayWhiteBalanceController implements AmbientSensor.AmbientBrightnessSensor.Callbacks, diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index a96e4adf1fee..0616f4e9d5ac 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -844,6 +844,10 @@ public class LockSettingsService extends ILockSettings.Stub { getAuthSecretHal(); mDeviceProvisionedObserver.onSystemReady(); + // Work around an issue in PropertyInvalidatedCache where the cache doesn't work until the + // first invalidation. This can be removed if PropertyInvalidatedCache is fixed. + LockPatternUtils.invalidateCredentialTypeCache(); + // TODO: maybe skip this for split system user mode. mStorage.prefetchUser(UserHandle.USER_SYSTEM); mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(), diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6df38098205a..ba4ec91d84df 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2491,16 +2491,6 @@ public class NotificationManagerService extends SystemService { getContext().registerReceiver(mReviewNotificationPermissionsReceiver, ReviewNotificationPermissionsReceiver.getFilter(), Context.RECEIVER_NOT_EXPORTED); - - mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, - new AppOpsManager.OnOpChangedInternalListener() { - @Override - public void onOpChanged(@NonNull String op, @NonNull String packageName, - int userId) { - mHandler.post( - () -> handleNotificationPermissionChange(packageName, userId)); - } - }); } /** @@ -3560,16 +3550,20 @@ public class NotificationManagerService extends SystemService { } mPermissionHelper.setNotificationPermission( pkg, UserHandle.getUserId(uid), enabled, true); + sendAppBlockStateChangedBroadcast(pkg, uid, !enabled); mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES) .setType(MetricsEvent.TYPE_ACTION) .setPackageName(pkg) .setSubtype(enabled ? 1 : 0)); mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled); + // Now, cancel any outstanding notifications that are part of a just-disabled app + if (!enabled) { + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, + UserHandle.getUserId(uid), REASON_PACKAGE_BANNED); + } - // Outstanding notifications from this package will be cancelled, and the package will - // be sent the ACTION_APP_BLOCK_STATE_CHANGED broadcast, as soon as we get the - // callback from AppOpsManager. + handleSavePolicyFile(); } /** @@ -5892,21 +5886,6 @@ public class NotificationManagerService extends SystemService { } }; - private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) { - int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId); - if (uid == INVALID_UID) { - Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId)); - return; - } - boolean hasPermission = mPermissionHelper.hasPermission(uid); - sendAppBlockStateChangedBroadcast(pkg, uid, !hasPermission); - if (!hasPermission) { - cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null, - /* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId, - REASON_PACKAGE_BANNED); - } - } - protected void checkNotificationListenerAccess() { if (!isCallerSystemOrPhone()) { getContext().enforceCallingPermission( diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 36a0b0c0d8e9..1f5bd3e0cc60 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -75,6 +75,7 @@ import android.util.StatsEvent; import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import com.android.internal.logging.MetricsLogger; @@ -108,30 +109,34 @@ public class ZenModeHelper { static final int RULE_LIMIT_PER_PACKAGE = 100; // pkg|userId => uid - protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>(); + @VisibleForTesting protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>(); private final Context mContext; private final H mHandler; private final SettingsObserver mSettingsObserver; private final AppOpsManager mAppOps; - @VisibleForTesting protected final NotificationManager mNotificationManager; + private final NotificationManager mNotificationManager; private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory; - @VisibleForTesting protected ZenModeConfig mDefaultConfig; + private ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final ZenModeFiltering mFiltering; - protected final RingerModeDelegate mRingerModeDelegate = new + private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate(); @VisibleForTesting protected final ZenModeConditions mConditions; - Object mConfigsLock = new Object(); + private final Object mConfigsArrayLock = new Object(); + @GuardedBy("mConfigsArrayLock") @VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>(); private final Metrics mMetrics = new Metrics(); private final ConditionProviders.Config mServiceConfig; - private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver; - @VisibleForTesting protected ZenModeEventLogger mZenModeEventLogger; + private final SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver; + private final ZenModeEventLogger mZenModeEventLogger; @VisibleForTesting protected int mZenMode; @VisibleForTesting protected NotificationManager.Policy mConsolidatedPolicy; private int mUser = UserHandle.USER_SYSTEM; + + private final Object mConfigLock = new Object(); + @GuardedBy("mConfigLock") @VisibleForTesting protected ZenModeConfig mConfig; @VisibleForTesting protected AudioManagerInternal mAudioManager; protected PackageManager mPm; @@ -159,7 +164,7 @@ public class ZenModeHelper { mDefaultConfig = readDefaultConfig(mContext.getResources()); updateDefaultAutomaticRuleNames(); mConfig = mDefaultConfig.copy(); - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { mConfigs.put(UserHandle.USER_SYSTEM, mConfig); } mConsolidatedPolicy = mConfig.toNotificationPolicy(); @@ -186,7 +191,7 @@ public class ZenModeHelper { public boolean matchesCallFilter(UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity, int callingUid) { - synchronized (mConfig) { + synchronized (mConfigLock) { return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConsolidatedPolicy, userHandle, extras, validator, contactsTimeoutMs, timeoutAffinity, callingUid); @@ -206,7 +211,7 @@ public class ZenModeHelper { } public boolean shouldIntercept(NotificationRecord record) { - synchronized (mConfig) { + synchronized (mConfigLock) { return mFiltering.shouldIntercept(mZenMode, mConsolidatedPolicy, record); } } @@ -221,7 +226,7 @@ public class ZenModeHelper { public void initZenMode() { if (DEBUG) Log.d(TAG, "initZenMode"); - synchronized (mConfig) { + synchronized (mConfigLock) { // "update" config to itself, which will have no effect in the case where a config // was read in via XML, but will initialize zen mode if nothing was read in and the // config remains the default. @@ -250,7 +255,7 @@ public class ZenModeHelper { public void onUserRemoved(int user) { if (user < UserHandle.USER_SYSTEM) return; if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user); - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { mConfigs.remove(user); } } @@ -268,7 +273,7 @@ public class ZenModeHelper { mUser = user; if (DEBUG) Log.d(TAG, reason + " u=" + user); ZenModeConfig config = null; - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { if (mConfigs.get(user) != null) { config = mConfigs.get(user).copy(); } @@ -278,7 +283,7 @@ public class ZenModeHelper { config = mDefaultConfig.copy(); config.user = user; } - synchronized (mConfig) { + synchronized (mConfigLock) { setConfigLocked(config, null, reason, Process.SYSTEM_UID, true); } cleanUpZenRules(); @@ -314,7 +319,7 @@ public class ZenModeHelper { public List<ZenRule> getZenRules() { List<ZenRule> rules = new ArrayList<>(); - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return rules; for (ZenRule rule : mConfig.automaticRules.values()) { if (canManageAutomaticZenRule(rule)) { @@ -327,7 +332,7 @@ public class ZenModeHelper { public AutomaticZenRule getAutomaticZenRule(String id) { ZenRule rule; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return null; rule = mConfig.automaticRules.get(id); } @@ -364,7 +369,7 @@ public class ZenModeHelper { } ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) { throw new AndroidRuntimeException("Could not create rule"); } @@ -387,7 +392,7 @@ public class ZenModeHelper { public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, String reason, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return false; if (DEBUG) { Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule @@ -419,7 +424,7 @@ public class ZenModeHelper { public boolean removeAutomaticZenRule(String id, String reason, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return false; newConfig = mConfig.copy(); ZenRule ruleToRemove = newConfig.automaticRules.get(id); @@ -450,7 +455,7 @@ public class ZenModeHelper { public boolean removeAutomaticZenRules(String packageName, String reason, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return false; newConfig = mConfig.copy(); for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { @@ -467,7 +472,7 @@ public class ZenModeHelper { public void setAutomaticZenRuleState(String id, Condition condition, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return; newConfig = mConfig.copy(); @@ -481,7 +486,7 @@ public class ZenModeHelper { public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return; newConfig = mConfig.copy(); @@ -491,6 +496,7 @@ public class ZenModeHelper { } } + @GuardedBy("mConfigLock") private void setAutomaticZenRuleStateLocked(ZenModeConfig config, List<ZenRule> rules, Condition condition, int callingUid, boolean fromSystemOrSystemUi) { if (rules == null || rules.isEmpty()) return; @@ -538,7 +544,7 @@ public class ZenModeHelper { return 0; } int count = 0; - synchronized (mConfig) { + synchronized (mConfigLock) { for (ZenRule rule : mConfig.automaticRules.values()) { if (cn.equals(rule.component) || cn.equals(rule.configurationActivity)) { count++; @@ -555,7 +561,7 @@ public class ZenModeHelper { return 0; } int count = 0; - synchronized (mConfig) { + synchronized (mConfigLock) { for (ZenRule rule : mConfig.automaticRules.values()) { if (pkg.equals(rule.getPkg())) { count++; @@ -588,19 +594,23 @@ public class ZenModeHelper { protected void updateDefaultZenRules(int callingUid, boolean fromSystemOrSystemUi) { updateDefaultAutomaticRuleNames(); - for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) { - ZenRule currRule = mConfig.automaticRules.get(defaultRule.id); - // if default rule wasn't user-modified nor enabled, use localized name - // instead of previous system name - if (currRule != null && !currRule.modified && !currRule.enabled - && !defaultRule.name.equals(currRule.name)) { - if (canManageAutomaticZenRule(currRule)) { - if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name " - + "from " + currRule.name + " to " + defaultRule.name); - // update default rule (if locale changed, name of rule will change) - currRule.name = defaultRule.name; - updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule), - "locale changed", callingUid, fromSystemOrSystemUi); + synchronized (mConfigLock) { + for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) { + ZenRule currRule = mConfig.automaticRules.get(defaultRule.id); + // if default rule wasn't user-modified nor enabled, use localized name + // instead of previous system name + if (currRule != null && !currRule.modified && !currRule.enabled + && !defaultRule.name.equals(currRule.name)) { + if (canManageAutomaticZenRule(currRule)) { + if (DEBUG) { + Slog.d(TAG, "Locale change - updating default zen rule name " + + "from " + currRule.name + " to " + defaultRule.name); + } + // update default rule (if locale changed, name of rule will change) + currRule.name = defaultRule.name; + updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule), + "locale changed", callingUid, fromSystemOrSystemUi); + } } } } @@ -686,7 +696,7 @@ public class ZenModeHelper { private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, boolean setRingerMode, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig == null) return; if (!Global.isValidZenMode(zenMode)) return; if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode) @@ -715,7 +725,7 @@ public class ZenModeHelper { void dump(ProtoOutputStream proto) { proto.write(ZenModeProto.ZEN_MODE, mZenMode); - synchronized (mConfig) { + synchronized (mConfigLock) { if (mConfig.manualRule != null) { mConfig.manualRule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS); } @@ -737,14 +747,14 @@ public class ZenModeHelper { pw.println(Global.zenModeToString(mZenMode)); pw.print(prefix); pw.println("mConsolidatedPolicy=" + mConsolidatedPolicy.toString()); - synchronized(mConfigsLock) { + synchronized (mConfigsArrayLock) { final int N = mConfigs.size(); for (int i = 0; i < N; i++) { dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i)); } } pw.print(prefix); pw.print("mUser="); pw.println(mUser); - synchronized (mConfig) { + synchronized (mConfigLock) { dump(pw, prefix, "mConfig", mConfig); } @@ -833,7 +843,7 @@ public class ZenModeHelper { Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId); } if (DEBUG) Log.d(TAG, reason); - synchronized (mConfig) { + synchronized (mConfigLock) { setConfigLocked(config, null, reason, Process.SYSTEM_UID, true); } } @@ -841,7 +851,7 @@ public class ZenModeHelper { public void writeXml(TypedXmlSerializer out, boolean forBackup, Integer version, int userId) throws IOException { - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { final int n = mConfigs.size(); for (int i = 0; i < n; i++) { if (forBackup && mConfigs.keyAt(i) != userId) { @@ -856,7 +866,9 @@ public class ZenModeHelper { * @return user-specified default notification policy for priority only do not disturb */ public Policy getNotificationPolicy() { - return getNotificationPolicy(mConfig); + synchronized (mConfigLock) { + return getNotificationPolicy(mConfig); + } } private static Policy getNotificationPolicy(ZenModeConfig config) { @@ -867,8 +879,8 @@ public class ZenModeHelper { * Sets the global notification policy used for priority only do not disturb */ public void setNotificationPolicy(Policy policy, int callingUid, boolean fromSystemOrSystemUi) { - if (policy == null || mConfig == null) return; - synchronized (mConfig) { + synchronized (mConfigLock) { + if (policy == null || mConfig == null) return; final ZenModeConfig newConfig = mConfig.copy(); newConfig.applyNotificationPolicy(policy); setConfigLocked(newConfig, null, "setNotificationPolicy", callingUid, @@ -881,7 +893,7 @@ public class ZenModeHelper { */ private void cleanUpZenRules() { long currentTime = System.currentTimeMillis(); - synchronized (mConfig) { + synchronized (mConfigLock) { final ZenModeConfig newConfig = mConfig.copy(); if (newConfig.automaticRules != null) { for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { @@ -906,7 +918,7 @@ public class ZenModeHelper { * @return a copy of the zen mode configuration */ public ZenModeConfig getConfig() { - synchronized (mConfig) { + synchronized (mConfigLock) { return mConfig.copy(); } } @@ -918,7 +930,8 @@ public class ZenModeHelper { return mConsolidatedPolicy.copy(); } - public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent, + @GuardedBy("mConfigLock") + private boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent, String reason, int callingUid, boolean fromSystemOrSystemUi) { return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/, callingUid, fromSystemOrSystemUi); @@ -926,11 +939,12 @@ public class ZenModeHelper { public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason, int callingUid, boolean fromSystemOrSystemUi) { - synchronized (mConfig) { + synchronized (mConfigLock) { setConfigLocked(config, triggeringComponent, reason, callingUid, fromSystemOrSystemUi); } } + @GuardedBy("mConfigLock") private boolean setConfigLocked(ZenModeConfig config, String reason, ComponentName triggeringComponent, boolean setRingerMode, int callingUid, boolean fromSystemOrSystemUi) { @@ -942,7 +956,7 @@ public class ZenModeHelper { } if (config.user != mUser) { // simply store away for background users - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { mConfigs.put(config.user, config); } if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user); @@ -951,7 +965,7 @@ public class ZenModeHelper { // handle CPS backed conditions - danger! may modify config mConditions.evaluateConfig(config, null, false /*processSubscriptions*/); - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { mConfigs.put(config.user, config); } if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable()); @@ -979,6 +993,7 @@ public class ZenModeHelper { * Carries out a config update (if needed) and (re-)evaluates the zen mode value afterwards. * If logging is enabled, will also request logging of the outcome of this change if needed. */ + @GuardedBy("mConfigLock") private void updateConfigAndZenModeLocked(ZenModeConfig config, String reason, boolean setRingerMode, int callingUid, boolean fromSystemOrSystemUi) { final boolean logZenModeEvents = mFlagResolver.isEnabled( @@ -993,7 +1008,7 @@ public class ZenModeHelper { } final String val = Integer.toString(config.hashCode()); Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); - evaluateZenMode(reason, setRingerMode); + evaluateZenModeLocked(reason, setRingerMode); // After all changes have occurred, log if requested if (logZenModeEvents) { ZenModeEventLogger.ZenModeInfo newInfo = new ZenModeEventLogger.ZenModeInfo( @@ -1025,7 +1040,8 @@ public class ZenModeHelper { } @VisibleForTesting - protected void evaluateZenMode(String reason, boolean setRingerMode) { + @GuardedBy("mConfigLock") + protected void evaluateZenModeLocked(String reason, boolean setRingerMode) { if (DEBUG) Log.d(TAG, "evaluateZenMode"); if (mConfig == null) return; final int policyHashBefore = mConsolidatedPolicy == null ? 0 @@ -1056,8 +1072,8 @@ public class ZenModeHelper { } private int computeZenMode() { - if (mConfig == null) return Global.ZEN_MODE_OFF; - synchronized (mConfig) { + synchronized (mConfigLock) { + if (mConfig == null) return Global.ZEN_MODE_OFF; if (mConfig.manualRule != null) return mConfig.manualRule.zenMode; int zen = Global.ZEN_MODE_OFF; for (ZenRule automaticRule : mConfig.automaticRules.values()) { @@ -1094,8 +1110,8 @@ public class ZenModeHelper { } private void updateConsolidatedPolicy(String reason) { - if (mConfig == null) return; - synchronized (mConfig) { + synchronized (mConfigLock) { + if (mConfig == null) return; ZenPolicy policy = new ZenPolicy(); if (mConfig.manualRule != null) { applyCustomPolicy(policy, mConfig.manualRule); @@ -1293,7 +1309,7 @@ public class ZenModeHelper { * Generate pulled atoms about do not disturb configurations. */ public void pullRules(List<StatsEvent> events) { - synchronized (mConfigsLock) { + synchronized (mConfigsArrayLock) { final int numConfigs = mConfigs.size(); for (int i = 0; i < numConfigs; i++) { final int user = mConfigs.keyAt(i); @@ -1319,6 +1335,7 @@ public class ZenModeHelper { } } + @GuardedBy("mConfigsArrayLock") private void ruleToProtoLocked(int user, ZenRule rule, boolean isManualRule, List<StatsEvent> events) { // Make the ID safe. @@ -1389,7 +1406,7 @@ public class ZenModeHelper { if (mZenMode == Global.ZEN_MODE_OFF || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS - && !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(mConfig))) { + && !areAllPriorityOnlyRingerSoundsMuted())) { // in priority only with ringer not muted, save ringer mode changes // in dnd off, save ringer mode changes setPreviousRingerModeSetting(ringerModeNew); @@ -1410,8 +1427,7 @@ public class ZenModeHelper { && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS || mZenMode == Global.ZEN_MODE_ALARMS || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS - && ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted( - mConfig)))) { + && areAllPriorityOnlyRingerSoundsMuted()))) { newZen = Global.ZEN_MODE_OFF; } else if (mZenMode != Global.ZEN_MODE_OFF) { ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT; @@ -1430,6 +1446,12 @@ public class ZenModeHelper { return ringerModeExternalOut; } + private boolean areAllPriorityOnlyRingerSoundsMuted() { + synchronized (mConfigLock) { + return ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(mConfig); + } + } + @Override public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeInternal, VolumePolicy policy) { @@ -1633,7 +1655,7 @@ public class ZenModeHelper { private void emitRules() { final long now = SystemClock.elapsedRealtime(); final long since = (now - mRuleCountLogTime); - synchronized (mConfig) { + synchronized (mConfigLock) { int numZenRules = mConfig.automaticRules.size(); if (mNumZenRules != numZenRules || since > MINIMUM_LOG_PERIOD_MS) { @@ -1651,7 +1673,7 @@ public class ZenModeHelper { private void emitDndType() { final long now = SystemClock.elapsedRealtime(); final long since = (now - mTypeLogTimeMs); - synchronized (mConfig) { + synchronized (mConfigLock) { boolean dndOn = mZenMode != Global.ZEN_MODE_OFF; int zenType = !dndOn ? DND_OFF : (mConfig.manualRule != null) ? DND_ON_MANUAL : DND_ON_AUTOMATIC; diff --git a/services/core/java/com/android/server/pm/DefaultAppProvider.java b/services/core/java/com/android/server/pm/DefaultAppProvider.java index c18d0e9ef35e..fc61451b0289 100644 --- a/services/core/java/com/android/server/pm/DefaultAppProvider.java +++ b/services/core/java/com/android/server/pm/DefaultAppProvider.java @@ -24,14 +24,10 @@ import android.os.Binder; import android.os.UserHandle; import android.util.Slog; -import com.android.internal.infra.AndroidFuture; import com.android.internal.util.CollectionUtils; import com.android.server.FgThread; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import java.util.function.Supplier; @@ -70,27 +66,19 @@ public class DefaultAppProvider { * Set the package name of the default browser. * * @param packageName package name of the default browser, or {@code null} to unset - * @param async whether the operation should be asynchronous * @param userId the user ID - * @return whether the default browser was successfully set. */ - public boolean setDefaultBrowser(@Nullable String packageName, boolean async, - @UserIdInt int userId) { - if (userId == UserHandle.USER_ALL) { - return false; - } + public void setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) { final RoleManager roleManager = mRoleManagerSupplier.get(); if (roleManager == null) { - return false; + return; } final UserHandle user = UserHandle.of(userId); final Executor executor = FgThread.getExecutor(); - final AndroidFuture<Void> future = new AndroidFuture<>(); final Consumer<Boolean> callback = successful -> { - if (successful) { - future.complete(null); - } else { - future.completeExceptionally(new RuntimeException()); + if (!successful) { + Slog.e(PackageManagerService.TAG, "Failed to set default browser to " + + packageName); } }; final long identity = Binder.clearCallingIdentity(); @@ -102,19 +90,9 @@ public class DefaultAppProvider { roleManager.clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, user, executor, callback); } - if (!async) { - try { - future.get(5, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - Slog.e(PackageManagerService.TAG, "Exception while setting default browser: " - + packageName, e); - return false; - } - } } finally { Binder.restoreCallingIdentity(identity); } - return true; } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2fc22bf79d91..dbc2fd89e58c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3535,6 +3535,18 @@ public class PackageManagerService implements PackageSender, TestUtilityService // within these users. mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId); + // Restore default browser setting if it is now installed. + String defaultBrowser; + synchronized (mLock) { + defaultBrowser = mSettings.getPendingDefaultBrowserLPr(userId); + } + if (Objects.equals(packageName, defaultBrowser)) { + mDefaultAppProvider.setDefaultBrowser(packageName, userId); + synchronized (mLock) { + mSettings.removePendingDefaultBrowserLPw(userId); + } + } + // Persistent preferred activity might have came into effect due to this // install. mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId); @@ -6732,7 +6744,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService @Override public String removeLegacyDefaultBrowserPackageName(int userId) { synchronized (mLock) { - return mSettings.removeDefaultBrowserPackageNameLPw(userId); + return mSettings.removePendingDefaultBrowserLPw(userId); } } @@ -7569,8 +7581,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService callback); } - void setDefaultBrowser(@Nullable String packageName, boolean async, @UserIdInt int userId) { - mDefaultAppProvider.setDefaultBrowser(packageName, async, userId); + @Nullable + String getDefaultBrowser(@UserIdInt int userId) { + return mDefaultAppProvider.getDefaultBrowser(userId); + } + + void setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) { + mDefaultAppProvider.setDefaultBrowser(packageName, userId); } PackageUsage getPackageUsage() { diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java index 214a8b80b35d..76e7070bd3fe 100644 --- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java +++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java @@ -557,9 +557,8 @@ final class PreferredActivityHelper { serializer.startDocument(null, true); serializer.startTag(null, TAG_DEFAULT_APPS); - synchronized (mPm.mLock) { - mPm.mSettings.writeDefaultAppsLPr(serializer, userId); - } + final String defaultBrowser = mPm.getDefaultBrowser(userId); + Settings.writeDefaultApps(serializer, defaultBrowser); serializer.endTag(null, TAG_DEFAULT_APPS); serializer.endDocument(); @@ -584,14 +583,19 @@ final class PreferredActivityHelper { parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name()); restoreFromXml(parser, userId, TAG_DEFAULT_APPS, (parser1, userId1) -> { - final String defaultBrowser; - synchronized (mPm.mLock) { - mPm.mSettings.readDefaultAppsLPw(parser1, userId1); - defaultBrowser = mPm.mSettings.removeDefaultBrowserPackageNameLPw( - userId1); - } + final String defaultBrowser = Settings.readDefaultApps(parser1); if (defaultBrowser != null) { - mPm.setDefaultBrowser(defaultBrowser, false, userId1); + final PackageStateInternal packageState = mPm.snapshotComputer() + .getPackageStateInternal(defaultBrowser); + if (packageState != null + && packageState.getUserStateOrDefault(userId1).isInstalled()) { + mPm.setDefaultBrowser(defaultBrowser, userId1); + } else { + synchronized (mPm.mLock) { + mPm.mSettings.setPendingDefaultBrowserLPw(defaultBrowser, + userId1); + } + } } }); } catch (Exception e) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 532ae718c030..677a5d11cc6b 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -517,9 +517,11 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile private final WatchedArrayMap<String, String> mRenamedPackages = new WatchedArrayMap<String, String>(); - // For every user, it is used to find the package name of the default Browser App. + // For every user, it is used to find the package name of the default browser app pending to be + // applied, either on first boot after upgrade, or after backup & restore but before app is + // installed. @Watched - final WatchedSparseArray<String> mDefaultBrowserApp = new WatchedSparseArray<String>(); + final WatchedSparseArray<String> mPendingDefaultBrowser = new WatchedSparseArray<>(); // TODO(b/161161364): This seems unused, and is probably not relevant in the new API, but should // verify. @@ -592,7 +594,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile mAppIds.registerObserver(mObserver); mRenamedPackages.registerObserver(mObserver); mNextAppLinkGeneration.registerObserver(mObserver); - mDefaultBrowserApp.registerObserver(mObserver); + mPendingDefaultBrowser.registerObserver(mObserver); mPendingPackages.registerObserver(mObserver); mPastSignatures.registerObserver(mObserver); mKeySetRefs.registerObserver(mObserver); @@ -787,7 +789,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile mRenamedPackages.snapshot(r.mRenamedPackages); mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration); - mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp); + mPendingDefaultBrowser.snapshot(r.mPendingDefaultBrowser); // mReadMessages mPendingPackages = r.mPendingPackagesSnapshot.snapshot(); mPendingPackagesSnapshot = new SnapshotCache.Sealed<>(); @@ -1504,8 +1506,16 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile return cpir; } - String removeDefaultBrowserPackageNameLPw(int userId) { - return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.removeReturnOld(userId); + String getPendingDefaultBrowserLPr(int userId) { + return mPendingDefaultBrowser.get(userId); + } + + void setPendingDefaultBrowserLPw(String defaultBrowser, int userId) { + mPendingDefaultBrowser.put(userId, defaultBrowser); + } + + String removePendingDefaultBrowserLPw(int userId) { + return mPendingDefaultBrowser.removeReturnOld(userId); } private File getUserSystemDirectory(int userId) { @@ -1688,6 +1698,19 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile void readDefaultAppsLPw(XmlPullParser parser, int userId) throws XmlPullParserException, IOException { + String defaultBrowser = readDefaultApps(parser); + if (defaultBrowser != null) { + mPendingDefaultBrowser.put(userId, defaultBrowser); + } + } + + /** + * @return the package name for the default browser app, or {@code null} if none. + */ + @Nullable + static String readDefaultApps(@NonNull XmlPullParser parser) + throws XmlPullParserException, IOException { + String defaultBrowser = null; int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -1697,8 +1720,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile } String tagName = parser.getName(); if (tagName.equals(TAG_DEFAULT_BROWSER)) { - String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); - mDefaultBrowserApp.put(userId, packageName); + defaultBrowser = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); } else if (tagName.equals(TAG_DEFAULT_DIALER)) { // Ignored. } else { @@ -1708,6 +1730,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile XmlUtils.skipCurrentTag(parser); } } + return defaultBrowser; } void readBlockUninstallPackagesLPw(TypedXmlPullParser parser, int userId) @@ -2087,8 +2110,13 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile void writeDefaultAppsLPr(XmlSerializer serializer, int userId) throws IllegalArgumentException, IllegalStateException, IOException { + String defaultBrowser = mPendingDefaultBrowser.get(userId); + writeDefaultApps(serializer, defaultBrowser); + } + + static void writeDefaultApps(@NonNull XmlSerializer serializer, @Nullable String defaultBrowser) + throws IllegalArgumentException, IllegalStateException, IOException { serializer.startTag(null, TAG_DEFAULT_APPS); - String defaultBrowser = mDefaultBrowserApp.get(userId); if (!TextUtils.isEmpty(defaultBrowser)) { serializer.startTag(null, TAG_DEFAULT_BROWSER); serializer.attribute(null, ATTR_PACKAGE_NAME, defaultBrowser); diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index 27329e20bc8d..6821c40ec5d3 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -16244,7 +16244,7 @@ public class BatteryStatsImpl extends BatteryStats { } NP = in.readInt(); - if (NP > 1000) { + if (NP > 10000) { throw new ParcelFormatException("File corrupt: too many processes " + NP); } for (int ip = 0; ip < NP; ip++) { diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index c5f63ced989c..a6d5c19395b0 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -285,9 +285,9 @@ class ActivityMetricsLogger { final LaunchingState mLaunchingState; /** The type can be cold (new process), warm (new activity), or hot (bring to front). */ - final int mTransitionType; + int mTransitionType; /** Whether the process was already running when the transition started. */ - final boolean mProcessRunning; + boolean mProcessRunning; /** whether the process of the launching activity didn't have any active activity. */ final boolean mProcessSwitch; /** The process state of the launching activity prior to the launch */ @@ -972,6 +972,19 @@ class ActivityMetricsLogger { // App isn't attached to record yet, so match with info. if (info.mLastLaunchedActivity.info.applicationInfo == appInfo) { info.mBindApplicationDelayMs = info.calculateCurrentDelay(); + if (info.mProcessRunning) { + // It was HOT/WARM launch, but the process was died somehow right after the + // launch request. + info.mProcessRunning = false; + info.mTransitionType = TYPE_TRANSITION_COLD_LAUNCH; + final String msg = "Process " + info.mLastLaunchedActivity.info.processName + + " restarted"; + Slog.i(TAG, msg); + if (info.mLaunchingState.mTraceName != null) { + Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, msg + "#" + + LaunchingState.sTraceSeqId); + } + } } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index dd6bcb1060ea..e9ff2a4edc79 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7994,6 +7994,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLastReportedConfiguration.getMergedConfiguration())) { ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */, false /* ignoreVisibility */, true /* isRequestedOrientationChanged */); + if (mTransitionController.inPlayingTransition(this)) { + mTransitionController.mValidateActivityCompat.add(this); + } } mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( @@ -9413,6 +9416,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (info.applicationInfo == null) { return info.getMinAspectRatio(); } + if (mLetterboxUiController.shouldApplyUserMinAspectRatioOverride()) { + return mLetterboxUiController.getUserMinAspectRatio(); + } if (!mLetterboxUiController.shouldOverrideMinAspectRatio()) { return info.getMinAspectRatio(); } diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 7a201a77c966..e945bc1babd9 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -294,16 +294,15 @@ final class LetterboxConfiguration { @NonNull private final SynchedDeviceConfig mDeviceConfig; LetterboxConfiguration(@NonNull final Context systemUiContext) { - this(systemUiContext, - new LetterboxConfigurationPersister(systemUiContext, - () -> readLetterboxHorizontalReachabilityPositionFromConfig( - systemUiContext, /* forBookMode */ false), - () -> readLetterboxVerticalReachabilityPositionFromConfig( - systemUiContext, /* forTabletopMode */ false), - () -> readLetterboxHorizontalReachabilityPositionFromConfig( - systemUiContext, /* forBookMode */ true), - () -> readLetterboxVerticalReachabilityPositionFromConfig( - systemUiContext, /* forTabletopMode */ true))); + this(systemUiContext, new LetterboxConfigurationPersister( + () -> readLetterboxHorizontalReachabilityPositionFromConfig( + systemUiContext, /* forBookMode */ false), + () -> readLetterboxVerticalReachabilityPositionFromConfig( + systemUiContext, /* forTabletopMode */ false), + () -> readLetterboxHorizontalReachabilityPositionFromConfig( + systemUiContext, /* forBookMode */ true), + () -> readLetterboxVerticalReachabilityPositionFromConfig( + systemUiContext, /* forTabletopMode */ true))); } @VisibleForTesting diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java index 756339701590..38aa903e3954 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java +++ b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java @@ -23,7 +23,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.Context; import android.os.Environment; import android.os.StrictMode; import android.os.StrictMode.ThreadPolicy; @@ -53,10 +52,8 @@ class LetterboxConfigurationPersister { private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxConfigurationPersister" : TAG_WM; - @VisibleForTesting - static final String LETTERBOX_CONFIGURATION_FILENAME = "letterbox_config"; + private static final String LETTERBOX_CONFIGURATION_FILENAME = "letterbox_config"; - private final Context mContext; private final Supplier<Integer> mDefaultHorizontalReachabilitySupplier; private final Supplier<Integer> mDefaultVerticalReachabilitySupplier; private final Supplier<Integer> mDefaultBookModeReachabilitySupplier; @@ -97,36 +94,32 @@ class LetterboxConfigurationPersister { @NonNull private final PersisterQueue mPersisterQueue; - LetterboxConfigurationPersister(Context systemUiContext, - Supplier<Integer> defaultHorizontalReachabilitySupplier, - Supplier<Integer> defaultVerticalReachabilitySupplier, - Supplier<Integer> defaultBookModeReachabilitySupplier, - Supplier<Integer> defaultTabletopModeReachabilitySupplier) { - this(systemUiContext, defaultHorizontalReachabilitySupplier, - defaultVerticalReachabilitySupplier, - defaultBookModeReachabilitySupplier, - defaultTabletopModeReachabilitySupplier, + LetterboxConfigurationPersister( + @NonNull Supplier<Integer> defaultHorizontalReachabilitySupplier, + @NonNull Supplier<Integer> defaultVerticalReachabilitySupplier, + @NonNull Supplier<Integer> defaultBookModeReachabilitySupplier, + @NonNull Supplier<Integer> defaultTabletopModeReachabilitySupplier) { + this(defaultHorizontalReachabilitySupplier, defaultVerticalReachabilitySupplier, + defaultBookModeReachabilitySupplier, defaultTabletopModeReachabilitySupplier, Environment.getDataSystemDirectory(), new PersisterQueue(), - /* completionCallback */ null); + /* completionCallback */ null, LETTERBOX_CONFIGURATION_FILENAME); } @VisibleForTesting - LetterboxConfigurationPersister(Context systemUiContext, - Supplier<Integer> defaultHorizontalReachabilitySupplier, - Supplier<Integer> defaultVerticalReachabilitySupplier, - Supplier<Integer> defaultBookModeReachabilitySupplier, - Supplier<Integer> defaultTabletopModeReachabilitySupplier, - File configFolder, - PersisterQueue persisterQueue, @Nullable Consumer<String> completionCallback) { - mContext = systemUiContext.createDeviceProtectedStorageContext(); + LetterboxConfigurationPersister( + @NonNull Supplier<Integer> defaultHorizontalReachabilitySupplier, + @NonNull Supplier<Integer> defaultVerticalReachabilitySupplier, + @NonNull Supplier<Integer> defaultBookModeReachabilitySupplier, + @NonNull Supplier<Integer> defaultTabletopModeReachabilitySupplier, + @NonNull File configFolder, @NonNull PersisterQueue persisterQueue, + @Nullable Consumer<String> completionCallback, + @NonNull String letterboxConfigurationFileName) { mDefaultHorizontalReachabilitySupplier = defaultHorizontalReachabilitySupplier; mDefaultVerticalReachabilitySupplier = defaultVerticalReachabilitySupplier; - mDefaultBookModeReachabilitySupplier = - defaultBookModeReachabilitySupplier; - mDefaultTabletopModeReachabilitySupplier = - defaultTabletopModeReachabilitySupplier; + mDefaultBookModeReachabilitySupplier = defaultBookModeReachabilitySupplier; + mDefaultTabletopModeReachabilitySupplier = defaultTabletopModeReachabilitySupplier; mCompletionCallback = completionCallback; - final File prefFiles = new File(configFolder, LETTERBOX_CONFIGURATION_FILENAME); + final File prefFiles = new File(configFolder, letterboxConfigurationFileName); mConfigurationFile = new AtomicFile(prefFiles); mPersisterQueue = persisterQueue; runWithDiskReadsThreadPolicy(this::readCurrentConfiguration); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 39f75703d71f..394105a646f1 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -40,6 +40,12 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.isFixedOrientation; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.screenOrientationToString; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; @@ -103,6 +109,7 @@ import android.content.res.Resources; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; +import android.os.RemoteException; import android.util.Slog; import android.view.InsetsSource; import android.view.InsetsState; @@ -237,6 +244,10 @@ final class LetterboxUiController { // Counter for ActivityRecord#setRequestedOrientation private int mSetOrientationRequestCounter = 0; + // The min aspect ratio override set by user + @PackageManager.UserMinAspectRatio + private int mUserAspectRatio = USER_MIN_ASPECT_RATIO_UNSET; + // The CompatDisplayInsets of the opaque activity beneath the translucent one. private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets; @@ -1059,7 +1070,7 @@ final class LetterboxUiController { private float getDefaultMinAspectRatioForUnresizableApps() { if (!mLetterboxConfiguration.getIsSplitScreenAspectRatioForUnresizableAppsEnabled() - || mActivityRecord.getDisplayContent() == null) { + || mActivityRecord.getDisplayArea() == null) { return mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps() > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO ? mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps() @@ -1071,8 +1082,8 @@ final class LetterboxUiController { float getSplitScreenAspectRatio() { // Getting the same aspect ratio that apps get in split screen. - final DisplayContent displayContent = mActivityRecord.getDisplayContent(); - if (displayContent == null) { + final DisplayArea displayArea = mActivityRecord.getDisplayArea(); + if (displayArea == null) { return getDefaultMinAspectRatioForUnresizableApps(); } int dividerWindowWidth = @@ -1080,7 +1091,7 @@ final class LetterboxUiController { int dividerInsets = getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_insets); int dividerSize = dividerWindowWidth - dividerInsets * 2; - final Rect bounds = new Rect(displayContent.getWindowConfiguration().getAppBounds()); + final Rect bounds = new Rect(displayArea.getWindowConfiguration().getAppBounds()); if (bounds.width() >= bounds.height()) { bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0); bounds.right = bounds.centerX(); @@ -1091,14 +1102,57 @@ final class LetterboxUiController { return computeAspectRatio(bounds); } + boolean shouldApplyUserMinAspectRatioOverride() { + if (!mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled()) { + return false; + } + + try { + final int userAspectRatio = mActivityRecord.mAtmService.getPackageManager() + .getUserMinAspectRatio(mActivityRecord.packageName, mActivityRecord.mUserId); + mUserAspectRatio = userAspectRatio; + return userAspectRatio != USER_MIN_ASPECT_RATIO_UNSET; + } catch (RemoteException e) { + // Don't apply user aspect ratio override + Slog.w(TAG, "Exception thrown retrieving aspect ratio user override " + this, e); + return false; + } + } + + float getUserMinAspectRatio() { + switch (mUserAspectRatio) { + case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: + return getDisplaySizeMinAspectRatio(); + case USER_MIN_ASPECT_RATIO_SPLIT_SCREEN: + return getSplitScreenAspectRatio(); + case USER_MIN_ASPECT_RATIO_16_9: + return 16 / 9f; + case USER_MIN_ASPECT_RATIO_4_3: + return 4 / 3f; + case USER_MIN_ASPECT_RATIO_3_2: + return 3 / 2f; + default: + throw new AssertionError("Unexpected user min aspect ratio override: " + + mUserAspectRatio); + } + } + + private float getDisplaySizeMinAspectRatio() { + final DisplayArea displayArea = mActivityRecord.getDisplayArea(); + if (displayArea == null) { + return mActivityRecord.info.getMinAspectRatio(); + } + final Rect bounds = new Rect(displayArea.getWindowConfiguration().getAppBounds()); + return computeAspectRatio(bounds); + } + private float getDefaultMinAspectRatio() { - final DisplayContent displayContent = mActivityRecord.getDisplayContent(); - if (displayContent == null + if (mActivityRecord.getDisplayArea() == null || !mLetterboxConfiguration .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()) { return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(); } - return computeAspectRatio(new Rect(displayContent.getBounds())); + return getDisplaySizeMinAspectRatio(); } Resources getResources() { diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 9ef5ed051a13..4faaf5170f27 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -682,6 +682,26 @@ class RecentTasks { } } + /** + * Removes the oldest recent task that is compatible with the given one. This is possible if + * the task windowing mode changed after being added to the Recents. + */ + void removeCompatibleRecentTask(Task task) { + final int taskIndex = mTasks.indexOf(task); + if (taskIndex < 0) { + return; + } + + final int candidateIndex = findRemoveIndexForTask(task, false /* includingSelf */); + if (candidateIndex == -1) { + // Nothing to trim + return; + } + + final Task taskToRemove = taskIndex > candidateIndex ? task : mTasks.get(candidateIndex); + remove(taskToRemove); + } + void removeTasksByPackageName(String packageName, int userId) { for (int i = mTasks.size() - 1; i >= 0; --i) { final Task task = mTasks.get(i); @@ -1540,6 +1560,10 @@ class RecentTasks { * list (if any). */ private int findRemoveIndexForAddTask(Task task) { + return findRemoveIndexForTask(task, true /* includingSelf */); + } + + private int findRemoveIndexForTask(Task task, boolean includingSelf) { final int recentsCount = mTasks.size(); final Intent intent = task.intent; final boolean document = intent != null && intent.isDocument(); @@ -1595,6 +1619,8 @@ class RecentTasks { // existing task continue; } + } else if (!includingSelf) { + continue; } return i; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index d9a954f1973b..05f95f813e55 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -3212,6 +3212,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> + "not idle", rootTask.getRootTaskId(), resumedActivity); return false; } + if (mTransitionController.isTransientLaunch(resumedActivity)) { + // Not idle if the transient transition animation is running. + return false; + } } // End power mode launch when idle. mService.endLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY); diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 0c1f33ccedbc..92c0987d5636 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1020,7 +1020,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { final WindowContainer<?> parent = getParent(); final Task thisTask = asTask(); if (thisTask != null && parent.asTask() == null - && mTransitionController.isTransientHide(thisTask)) { + && mTransitionController.isTransientVisible(thisTask)) { // Keep transient-hide root tasks visible. Non-root tasks still follow standard rule. return TASK_FRAGMENT_VISIBILITY_VISIBLE; } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 71192cd5a3be..84f168ff0810 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -407,6 +407,36 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return false; } + /** Returns {@code true} if the task should keep visible if this is a transient transition. */ + boolean isTransientVisible(@NonNull Task task) { + if (mTransientLaunches == null) return false; + int occludedCount = 0; + final int numTransient = mTransientLaunches.size(); + for (int i = numTransient - 1; i >= 0; --i) { + final Task transientRoot = mTransientLaunches.keyAt(i).getRootTask(); + if (transientRoot == null) continue; + final WindowContainer<?> rootParent = transientRoot.getParent(); + if (rootParent == null || rootParent.getTopChild() == transientRoot) continue; + final ActivityRecord topOpaque = mController.mAtm.mTaskSupervisor + .mOpaqueActivityHelper.getOpaqueActivity(rootParent); + if (transientRoot.compareTo(topOpaque.getRootTask()) < 0) { + occludedCount++; + } + } + if (occludedCount == numTransient) { + for (int i = mTransientLaunches.size() - 1; i >= 0; --i) { + if (mTransientLaunches.keyAt(i).isDescendantOf(task)) { + // Keep transient activity visible until transition finished, so it won't pause + // with transient-hide tasks that may delay resuming the next top. + return true; + } + } + // Let transient-hide activities pause before transition is finished. + return false; + } + return isInTransientHide(task); + } + boolean canApplyDim(@NonNull Task task) { if (mTransientLaunches == null) return true; final Dimmer dimmer = task.getDimmer(); diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 79cb61be5948..37985ea0aa6a 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -30,6 +30,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IApplicationThread; import android.app.WindowConfiguration; +import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -141,6 +142,14 @@ class TransitionController { final ArrayList<ActivityRecord> mValidateCommitVis = new ArrayList<>(); /** + * List of activity-level participants. ActivityRecord is not expected to change independently, + * however, recent compatibility logic can now cause this at arbitrary times determined by + * client code. If it happens during an animation, the surface can be left at the wrong spot. + * TODO(b/290237710) remove when compat logic is moved. + */ + final ArrayList<ActivityRecord> mValidateActivityCompat = new ArrayList<>(); + + /** * Currently playing transitions (in the order they were started). When finished, records are * removed from this list. */ @@ -468,15 +477,22 @@ class TransitionController { if (mCollectingTransition != null && mCollectingTransition.isInTransientHide(task)) { return true; } - for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) { - if (mWaitingTransitions.get(i).isInTransientHide(task)) return true; - } for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { if (mPlayingTransitions.get(i).isInTransientHide(task)) return true; } return false; } + boolean isTransientVisible(@NonNull Task task) { + if (mCollectingTransition != null && mCollectingTransition.isTransientVisible(task)) { + return true; + } + for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { + if (mPlayingTransitions.get(i).isTransientVisible(task)) return true; + } + return false; + } + boolean canApplyDim(@Nullable Task task) { if (task == null) { // Always allow non-activity window. @@ -896,6 +912,14 @@ class TransitionController { } } mValidateCommitVis.clear(); + for (int i = 0; i < mValidateActivityCompat.size(); ++i) { + ActivityRecord ar = mValidateActivityCompat.get(i); + if (ar.getSurfaceControl() == null) continue; + final Point tmpPos = new Point(); + ar.getRelativePosition(tmpPos); + ar.getSyncTransaction().setPosition(ar.getSurfaceControl(), tmpPos.x, tmpPos.y); + } + mValidateActivityCompat.clear(); } /** diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 541fa9413f45..5d239eb993af 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1615,6 +1615,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final int count = tasksToReparent.size(); for (int i = 0; i < count; ++i) { final Task task = tasksToReparent.get(i); + final int prevWindowingMode = task.getWindowingMode(); if (syncId >= 0) { addToSyncSet(syncId, task); } @@ -1628,6 +1629,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, false /*moveParents*/, "processChildrenTaskReparentHierarchyOp"); } + // Trim the compatible Recent task (if any) after the Task is reparented and now has + // a different windowing mode, in order to prevent redundant Recent tasks after + // reparenting. + if (prevWindowingMode != task.getWindowingMode()) { + mService.mTaskSupervisor.mRecentTasks.removeCompatibleRecentTask(task); + } } if (transition != null) transition.collect(newParent); diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java index 081f19d19f75..d8569f75996f 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java @@ -21,8 +21,8 @@ import static org.junit.Assert.assertEquals; import android.hardware.display.DisplayManagerInternal; import android.view.Display; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessReason; @@ -46,7 +46,8 @@ public class FollowerBrightnessStrategyTest { DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest(); float brightnessToFollow = 0.2f; - mFollowerBrightnessStrategy.setBrightnessToFollow(brightnessToFollow); + boolean slowChange = true; + mFollowerBrightnessStrategy.setBrightnessToFollow(brightnessToFollow, slowChange); BrightnessReason brightnessReason = new BrightnessReason(); brightnessReason.setReason(BrightnessReason.REASON_FOLLOWER); DisplayBrightnessState expectedDisplayBrightnessState = @@ -55,6 +56,7 @@ public class FollowerBrightnessStrategyTest { .setBrightnessReason(brightnessReason) .setSdrBrightness(brightnessToFollow) .setDisplayBrightnessStrategyName(mFollowerBrightnessStrategy.getName()) + .setIsSlowChange(slowChange) .build(); DisplayBrightnessState updatedDisplayBrightnessState = mFollowerBrightnessStrategy.updateBrightness(displayPowerRequest); 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 73eb237fa9e7..410ae35aa790 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -125,6 +125,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; @@ -327,7 +328,7 @@ public class BroadcastQueueTest { eq(ActivityManager.PROCESS_STATE_LAST_ACTIVITY), any()); mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS); - mConstants.TIMEOUT = 100; + mConstants.TIMEOUT = 200; mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0; mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS = 500; @@ -707,6 +708,9 @@ public class BroadcastQueueTest { private void waitForIdle() throws Exception { mLooper.release(); mQueue.waitForIdle(LOG_WRITER_INFO); + final CountDownLatch latch = new CountDownLatch(1); + mHandlerThread.getThreadHandler().post(latch::countDown); + latch.await(); mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation() .acquireLooperManager(mHandlerThread.getLooper())); } @@ -2342,6 +2346,7 @@ public class BroadcastQueueTest { mUidObserver.onUidStateChanged(receiverGreenApp.info.uid, ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE); + waitForIdle(); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK); @@ -2375,6 +2380,7 @@ public class BroadcastQueueTest { mUidObserver.onUidStateChanged(receiverGreenApp.info.uid, ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE); + waitForIdle(); final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK); 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 1f4563fb2682..9545a8a4544b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -68,7 +68,6 @@ import static com.android.server.am.ProcessList.UNKNOWN_ADJ; import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.AdditionalAnswers.answer; @@ -2522,28 +2521,6 @@ public class MockingOomAdjusterTests { @SuppressWarnings("GuardedBy") @Test - public void testUpdateOomAdj_DoOne_AboveClient_SameProcess() { - ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, - MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState(); - doReturn(app).when(sService).getTopApp(); - sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); - - assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); - - // Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and - // verify that its OOM adjustment level is unaffected. - bindService(app, app, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class)); - app.mServices.updateHasAboveClientLocked(); - assertFalse(app.mServices.hasAboveClient()); - - sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); - assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); - } - - @SuppressWarnings("GuardedBy") - @Test public void testUpdateOomAdj_DoAll_Side_Cycle() { final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java index 95c62aeec19a..7e69357ed006 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java @@ -86,7 +86,9 @@ public class DisplayBrightnessStateTest { .append("\n brightnessReason:") .append(displayBrightnessState.getBrightnessReason()) .append("\n shouldUseAutoBrightness:") - .append(displayBrightnessState.getShouldUseAutoBrightness()); + .append(displayBrightnessState.getShouldUseAutoBrightness()) + .append("\n isSlowChange:") + .append(displayBrightnessState.isSlowChange()); return sb.toString(); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java index c710d1c3885d..56f650ee9084 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -121,7 +121,8 @@ public final class DisplayPowerController2Test { private PowerManager mPowerManagerMock; @Mock private ColorDisplayService.ColorDisplayServiceInternal mCdsiMock; - + @Mock + private DisplayWhiteBalanceController mDisplayWhiteBalanceControllerMock; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; @@ -1089,6 +1090,18 @@ public final class DisplayPowerController2Test { .getThermalBrightnessThrottlingDataMapByThrottlingId(); } + @Test + public void testDwbcCallsHappenOnHandler() { + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + + mHolder.dpc.setAutomaticScreenBrightnessMode(true); + verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true); + + // dispatch handler looper + advanceTime(1); + verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true); + } + /** * Creates a mock and registers it to {@link LocalServices}. */ @@ -1378,5 +1391,11 @@ public final class DisplayPowerController2Test { Context context) { return mHighBrightnessModeController; } + + @Override + DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, + SensorManager sensorManager, Resources resources) { + return mDisplayWhiteBalanceControllerMock; + } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java index 7d26913bd390..e2aeea3bedba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -121,7 +121,8 @@ public final class DisplayPowerControllerTest { private PowerManager mPowerManagerMock; @Mock private ColorDisplayService.ColorDisplayServiceInternal mCdsiMock; - + @Mock + private DisplayWhiteBalanceController mDisplayWhiteBalanceControllerMock; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; @@ -1092,6 +1093,18 @@ public final class DisplayPowerControllerTest { .getThermalBrightnessThrottlingDataMapByThrottlingId(); } + @Test + public void testDwbcCallsHappenOnHandler() { + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + + mHolder.dpc.setAutomaticScreenBrightnessMode(true); + verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true); + + // dispatch handler looper + advanceTime(1); + verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true); + } + /** * Creates a mock and registers it to {@link LocalServices}. */ @@ -1351,5 +1364,11 @@ public final class DisplayPowerControllerTest { Context context) { return mHighBrightnessModeController; } + + @Override + DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, + SensorManager sensorManager, Resources resources) { + return mDisplayWhiteBalanceControllerMock; + } } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java index 2d4bf144155c..32d0c98d4481 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java @@ -44,8 +44,10 @@ import android.annotation.NonNull; import android.graphics.PointF; import android.os.Handler; import android.os.Message; +import android.os.UserHandle; import android.os.VibrationEffect; import android.os.Vibrator; +import android.provider.Settings; import android.testing.TestableContext; import android.util.DebugUtils; import android.view.InputDevice; @@ -140,8 +142,6 @@ public class FullScreenMagnificationGestureHandlerTest { @Mock WindowMagnificationPromptController mWindowMagnificationPromptController; @Mock - AccessibilityManagerService mMockAccessibilityManagerService; - @Mock AccessibilityTraceManager mMockTraceManager; @Rule @@ -153,6 +153,8 @@ public class FullScreenMagnificationGestureHandlerTest { private long mLastDownTime = Integer.MIN_VALUE; + private float mOriginalMagnificationPersistedScale; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -166,6 +168,13 @@ public class FullScreenMagnificationGestureHandlerTest { when(mockController.newValueAnimator()).thenReturn(new ValueAnimator()); when(mockController.getAnimationDuration()).thenReturn(1000L); when(mockWindowManager.setMagnificationCallbacks(eq(DISPLAY_0), any())).thenReturn(true); + mOriginalMagnificationPersistedScale = Settings.Secure.getFloatForUser( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.0f, + UserHandle.USER_SYSTEM); + Settings.Secure.putFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.0f, + UserHandle.USER_SYSTEM); mFullScreenMagnificationController = new FullScreenMagnificationController( mockController, new Object(), @@ -192,6 +201,10 @@ public class FullScreenMagnificationGestureHandlerTest { mMgh.onDestroy(); mFullScreenMagnificationController.unregister(DISPLAY_0); verify(mWindowMagnificationPromptController).onDestroy(); + Settings.Secure.putFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, + mOriginalMagnificationPersistedScale, + UserHandle.USER_SYSTEM); } @NonNull @@ -525,10 +538,9 @@ public class FullScreenMagnificationGestureHandlerTest { final float threshold = FullScreenMagnificationGestureHandler.PanningScalingState .CHECK_DETECTING_PASS_PERSISTED_SCALE_THRESHOLD; final float persistedScale = (1.0f + threshold) * scale + 1.0f; - mFullScreenMagnificationController.setScale(DISPLAY_0, persistedScale, DEFAULT_X, - DEFAULT_Y, /* animate= */ false, - AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); - mFullScreenMagnificationController.persistScale(DISPLAY_0); + Settings.Secure.putFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, persistedScale, + UserHandle.USER_SYSTEM); mFullScreenMagnificationController.setScale(DISPLAY_0, scale, DEFAULT_X, DEFAULT_Y, /* animate= */ false, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); @@ -547,10 +559,9 @@ public class FullScreenMagnificationGestureHandlerTest { final float threshold = FullScreenMagnificationGestureHandler.PanningScalingState .CHECK_DETECTING_PASS_PERSISTED_SCALE_THRESHOLD; final float persistedScale = (1.0f + threshold) * scale - 0.1f; - mFullScreenMagnificationController.setScale(DISPLAY_0, persistedScale, DEFAULT_X, - DEFAULT_Y, /* animate= */ false, - AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); - mFullScreenMagnificationController.persistScale(DISPLAY_0); + Settings.Secure.putFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, persistedScale, + UserHandle.USER_SYSTEM); mFullScreenMagnificationController.setScale(DISPLAY_0, scale, DEFAULT_X, DEFAULT_Y, /* animate= */ false, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 68217219e453..fc62e75b7d59 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -16,6 +16,7 @@ package com.android.server.biometrics; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.Authenticators; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; @@ -113,6 +114,10 @@ public class BiometricServiceTest { private static final String ERROR_UNABLE_TO_PROCESS = "error_unable_to_process"; private static final String ERROR_USER_CANCELED = "error_user_canceled"; private static final String ERROR_LOCKOUT = "error_lockout"; + private static final String FACE_SUBTITLE = "face_subtitle"; + private static final String FINGERPRINT_SUBTITLE = "fingerprint_subtitle"; + private static final String DEFAULT_SUBTITLE = "default_subtitle"; + private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty"; @@ -191,6 +196,12 @@ public class BiometricServiceTest { .thenReturn(ERROR_NOT_RECOGNIZED); when(mResources.getString(R.string.biometric_error_user_canceled)) .thenReturn(ERROR_USER_CANCELED); + when(mContext.getString(R.string.biometric_dialog_face_subtitle)) + .thenReturn(FACE_SUBTITLE); + when(mContext.getString(R.string.biometric_dialog_fingerprint_subtitle)) + .thenReturn(FINGERPRINT_SUBTITLE); + when(mContext.getString(R.string.biometric_dialog_default_subtitle)) + .thenReturn(DEFAULT_SUBTITLE); when(mWindowManager.getDefaultDisplay()).thenReturn( new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY, @@ -211,7 +222,7 @@ public class BiometricServiceTest { @Test public void testClientBinderDied_whenPaused() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, true /* requireConfirmation */, null /* authenticators */); @@ -238,7 +249,7 @@ public class BiometricServiceTest { @Test public void testClientBinderDied_whenAuthenticating() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, true /* requireConfirmation */, null /* authenticators */); @@ -374,7 +385,7 @@ public class BiometricServiceTest { final int[] modalities = new int[] { TYPE_FINGERPRINT, - BiometricAuthenticator.TYPE_FACE, + TYPE_FACE, }; final int[] strengths = new int[] { @@ -427,9 +438,56 @@ public class BiometricServiceTest { } @Test + public void testAuthenticateFace_shouldShowSubtitleForFace() throws Exception { + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, + null); + waitForIdle(); + + assertEquals(FACE_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle()); + } + + @Test + public void testAuthenticateFingerprint_shouldShowSubtitleForFingerprint() throws Exception { + setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG); + + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, + null); + waitForIdle(); + + assertEquals(FINGERPRINT_SUBTITLE, + mBiometricService.mAuthSession.mPromptInfo.getSubtitle()); + } + + @Test + public void testAuthenticateBothFpAndFace_shouldShowDefaultSubtitle() throws Exception { + final int[] modalities = new int[] { + TYPE_FINGERPRINT, + TYPE_FACE, + }; + + final int[] strengths = new int[] { + Authenticators.BIOMETRIC_WEAK, + Authenticators.BIOMETRIC_STRONG, + }; + + setupAuthForMultiple(modalities, strengths); + + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, + null); + waitForIdle(); + + assertEquals(DEFAULT_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle()); + } + + @Test public void testAuthenticateFace_respectsUserSetting() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); // Disabled in user settings receives onError when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false); @@ -568,7 +626,7 @@ public class BiometricServiceTest { @Test public void testAuthenticate_noBiometrics_credentialAllowed() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false); when(mTrustManager.isDeviceSecure(anyInt(), anyInt())) .thenReturn(true); @@ -595,13 +653,13 @@ public class BiometricServiceTest { @Test public void testAuthenticate_happyPathWithConfirmation_strongBiometric() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); testAuthenticate_happyPathWithConfirmation(true /* isStrongBiometric */); } @Test public void testAuthenticate_happyPathWithConfirmation_weakBiometric() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_WEAK); testAuthenticate_happyPathWithConfirmation(false /* isStrongBiometric */); } @@ -637,7 +695,7 @@ public class BiometricServiceTest { @Test public void testAuthenticate_no_Biometrics_noCredential() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false); when(mTrustManager.isDeviceSecure(anyInt(), anyInt())) .thenReturn(false); @@ -655,7 +713,7 @@ public class BiometricServiceTest { @Test public void testRejectFace_whenAuthenticating_notifiesSystemUIAndClient_thenPaused() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); @@ -663,7 +721,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mStatusBarService).onBiometricError( - eq(BiometricAuthenticator.TYPE_FACE), + eq(TYPE_FACE), eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED), eq(0 /* vendorCode */)); verify(mReceiver1).onAuthenticationFailed(); @@ -691,7 +749,7 @@ public class BiometricServiceTest { @Test public void testRequestAuthentication_whenAlreadyAuthenticating() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); @@ -700,7 +758,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mReceiver1).onError( - eq(BiometricAuthenticator.TYPE_FACE), + eq(TYPE_FACE), eq(BiometricPrompt.BIOMETRIC_ERROR_CANCELED), eq(0) /* vendorCode */); verify(mBiometricService.mStatusBarService).hideAuthenticationDialog(eq(TEST_REQUEST_ID)); @@ -710,7 +768,7 @@ public class BiometricServiceTest { @Test public void testErrorHalTimeout_whenAuthenticating_entersPausedState() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); @@ -723,7 +781,7 @@ public class BiometricServiceTest { assertEquals(STATE_AUTH_PAUSED, mBiometricService.mAuthSession.getState()); verify(mBiometricService.mStatusBarService).onBiometricError( - eq(BiometricAuthenticator.TYPE_FACE), + eq(TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_TIMEOUT), eq(0 /* vendorCode */)); // Timeout does not count as fail as per BiometricPrompt documentation. @@ -759,7 +817,7 @@ public class BiometricServiceTest { @Test public void testErrorFromHal_whenPaused_notifiesSystemUIAndClient() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); @@ -777,7 +835,7 @@ public class BiometricServiceTest { // Client receives error immediately verify(mReceiver1).onError( - eq(BiometricAuthenticator.TYPE_FACE), + eq(TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), eq(0 /* vendorCode */)); // Dialog is hidden immediately @@ -926,7 +984,7 @@ public class BiometricServiceTest { int biometricPromptError) throws Exception { final int[] modalities = new int[] { TYPE_FINGERPRINT, - BiometricAuthenticator.TYPE_FACE, + TYPE_FACE, }; final int[] strengths = new int[] { @@ -1123,7 +1181,7 @@ public class BiometricServiceTest { @Test public void testDismissedReasonNegative_whilePaused_invokeHalCancel() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); @@ -1142,7 +1200,7 @@ public class BiometricServiceTest { @Test public void testDismissedReasonUserCancel_whilePaused_invokesHalCancel() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, null /* authenticators */); @@ -1161,7 +1219,7 @@ public class BiometricServiceTest { @Test public void testDismissedReasonUserCancel_whenPendingConfirmation() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, true /* requireConfirmation */, null /* authenticators */); @@ -1175,7 +1233,7 @@ public class BiometricServiceTest { verify(mBiometricService.mSensors.get(0).impl) .cancelAuthenticationFromService(any(), any(), anyLong()); verify(mReceiver1).onError( - eq(BiometricAuthenticator.TYPE_FACE), + eq(TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), eq(0 /* vendorCode */)); verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class)); @@ -1296,7 +1354,7 @@ public class BiometricServiceTest { @Test public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false); when(mTrustManager.isDeviceSecure(anyInt(), anyInt())) .thenReturn(true); @@ -1590,7 +1648,7 @@ public class BiometricServiceTest { @Test public void testWorkAuthentication_faceWorksIfNotDisabledByDevicePolicyManager() throws Exception { - setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); when(mDevicePolicyManager .getKeyguardDisabledFeatures(any() /* admin*/, anyInt() /* userHandle */)) .thenReturn(~DevicePolicyManager.KEYGUARD_DISABLE_FACE); @@ -1683,7 +1741,7 @@ public class BiometricServiceTest { mFingerprintAuthenticator); } - if ((modality & BiometricAuthenticator.TYPE_FACE) != 0) { + if ((modality & TYPE_FACE) != 0) { when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(enrolled); when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true); when(mFaceAuthenticator.getLockoutModeForUser(anyInt())) @@ -1715,7 +1773,7 @@ public class BiometricServiceTest { strength, mFingerprintAuthenticator); } - if ((modality & BiometricAuthenticator.TYPE_FACE) != 0) { + if ((modality & TYPE_FACE) != 0) { when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true); mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality, @@ -1798,6 +1856,7 @@ public class BiometricServiceTest { boolean checkDevicePolicy) { final PromptInfo promptInfo = new PromptInfo(); promptInfo.setConfirmationRequested(requireConfirmation); + promptInfo.setUseDefaultSubtitle(true); if (authenticators != null) { promptInfo.setAuthenticators(authenticators); diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING new file mode 100644 index 000000000000..0ffa891ce3e1 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.contentcapture" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +} diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING new file mode 100644 index 000000000000..419508ca5e17 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.contentprotection" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 3c882dc871fd..f552ab2dab60 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -73,6 +73,7 @@ import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; +import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; @@ -405,7 +406,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { UriGrantsManagerInternal mUgmInternal; @Mock AppOpsManager mAppOpsManager; - private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener; @Mock private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; @@ -605,12 +605,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName, SEARCH_SELECTOR_PKG); - doAnswer(invocation -> { - mOnPermissionChangeListener = invocation.getArgument(2); - return null; - }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(), - any()); - mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper())); mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, @@ -2009,10 +2003,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); - Thread.sleep(1); // make sure the system clock advances before the next step + mTestableLooper.moveTimeForward(1); // THEN it is canceled mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); - Thread.sleep(1); // here too + mTestableLooper.moveTimeForward(1); // THEN it is posted again (before the cancel has a chance to finish) mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); @@ -2303,7 +2297,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; mService.addNotification(notif); mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, - notif.getUserId(), 0); + notif.getUserId(), REASON_CANCEL); waitForIdle(); StatusBarNotification[] notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); @@ -3041,7 +3035,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; mService.addNotification(notif); mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, - Notification.FLAG_ONGOING_EVENT, notif.getUserId(), 0); + Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL); waitForIdle(); StatusBarNotification[] notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); @@ -3069,7 +3063,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; mService.addNotification(notif); mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, - notif.getUserId(), 0); + notif.getUserId(), REASON_CANCEL); waitForIdle(); StatusBarNotification[] notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); @@ -3223,6 +3217,48 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testUpdateAppNotifyCreatorBlock() throws Exception { + when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); + + mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false); + Thread.sleep(500); + waitForIdle(); + + ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); + + assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, + captor.getValue().getAction()); + assertEquals(PKG, captor.getValue().getPackage()); + assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); + } + + @Test + public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception { + when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); + + mBinderService.setNotificationsEnabledForPackage(PKG, 0, false); + verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); + } + + @Test + public void testUpdateAppNotifyCreatorUnblock() throws Exception { + when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); + + mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true); + Thread.sleep(500); + waitForIdle(); + + ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); + + assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, + captor.getValue().getAction()); + assertEquals(PKG, captor.getValue().getPackage()); + assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); + } + + @Test public void testUpdateChannelNotifyCreatorBlock() throws Exception { mService.setPreferencesHelper(mPreferencesHelper); when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), @@ -12138,134 +12174,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); } - @Test - public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage() - throws RemoteException { - // Have preexisting posted notifications from revoked package and other packages. - mService.addNotification(new NotificationRecord(mContext, - generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel)); - mService.addNotification(new NotificationRecord(mContext, - generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); - // Have preexisting enqueued notifications from revoked package and other packages. - mService.addEnqueuedNotification(new NotificationRecord(mContext, - generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel)); - mService.addEnqueuedNotification(new NotificationRecord(mContext, - generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); - assertThat(mService.mNotificationList).hasSize(2); - assertThat(mService.mEnqueuedNotifications).hasSize(2); - - when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001); - when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false); - - mOnPermissionChangeListener.onOpChanged( - AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0); - waitForIdle(); - - assertThat(mService.mNotificationList).hasSize(1); - assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other"); - assertThat(mService.mEnqueuedNotifications).hasSize(1); - assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo( - "other"); - } - - @Test - public void onOpChanged_permissionStillGranted_notificationsAreNotAffected() - throws RemoteException { - // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission - // being now granted, AND having previously posted notifications from said package) should - // never happen (if we trust the broadcasts are correct). So this test is for a what-if - // scenario, to verify we still handle it reasonably. - - // Have preexisting posted notifications from specific package and other packages. - mService.addNotification(new NotificationRecord(mContext, - generateSbn("granted", 1001, 1, 0), mTestNotificationChannel)); - mService.addNotification(new NotificationRecord(mContext, - generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); - // Have preexisting enqueued notifications from specific package and other packages. - mService.addEnqueuedNotification(new NotificationRecord(mContext, - generateSbn("granted", 1001, 3, 0), mTestNotificationChannel)); - mService.addEnqueuedNotification(new NotificationRecord(mContext, - generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); - assertThat(mService.mNotificationList).hasSize(2); - assertThat(mService.mEnqueuedNotifications).hasSize(2); - - when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001); - when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true); - - mOnPermissionChangeListener.onOpChanged( - AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0); - waitForIdle(); - - assertThat(mService.mNotificationList).hasSize(2); - assertThat(mService.mEnqueuedNotifications).hasSize(2); - } - - @Test - public void onOpChanged_permissionGranted_notifiesAppUnblocked() throws Exception { - when(mPackageManagerInternal.getPackageUid(PKG, 0, 0)).thenReturn(1001); - when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true); - - mOnPermissionChangeListener.onOpChanged( - AppOpsManager.OPSTR_POST_NOTIFICATION, PKG, 0); - waitForIdle(); - Thread.sleep(600); - waitForIdle(); - - ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); - verify(mContext).sendBroadcastAsUser(captor.capture(), any(), eq(null)); - assertThat(captor.getValue().getAction()).isEqualTo( - NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED); - assertThat(captor.getValue().getPackage()).isEqualTo(PKG); - assertThat(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)).isFalse(); - } - - @Test - public void onOpChanged_permissionRevoked_notifiesAppBlocked() throws Exception { - when(mPackageManagerInternal.getPackageUid(PKG, 0, 0)).thenReturn(1001); - when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false); - - mOnPermissionChangeListener.onOpChanged( - AppOpsManager.OPSTR_POST_NOTIFICATION, PKG, 0); - waitForIdle(); - Thread.sleep(600); - waitForIdle(); - - ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); - verify(mContext).sendBroadcastAsUser(captor.capture(), any(), eq(null)); - assertThat(captor.getValue().getAction()).isEqualTo( - NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED); - assertThat(captor.getValue().getPackage()).isEqualTo(PKG); - assertThat(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)).isTrue(); - } - - @Test - public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception { - mService.addNotification(new NotificationRecord(mContext, - generateSbn("package", 1001, 1, 0), mTestNotificationChannel)); - assertThat(mService.mNotificationList).hasSize(1); - when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001); - when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn( - true); - - // Start with granted permission and simulate effect of revoking it. - when(mPermissionHelper.hasPermission(1001)).thenReturn(true); - doAnswer(invocation -> { - when(mPermissionHelper.hasPermission(1001)).thenReturn(false); - mOnPermissionChangeListener.onOpChanged( - AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); - return null; - }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true); - - mBinderService.setNotificationsEnabledForPackage("package", 1001, false); - waitForIdle(); - - assertThat(mService.mNotificationList).hasSize(0); - - Thread.sleep(600); - waitForIdle(); - verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null)); - } - private static <T extends Parcelable> T parcelAndUnparcel(T source, Parcelable.Creator<T> creator) { Parcel parcel = Parcel.obtain(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index dedb8f170ee0..3ee75de23fdb 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -771,7 +771,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConfig = null; // will evaluate config to zen mode off for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer - mZenModeHelper.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenModeLocked("test", true); } verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, mZenModeHelper.TAG); @@ -798,7 +798,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer - mZenModeHelper.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenModeLocked("test", true); } verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, mZenModeHelper.TAG); @@ -825,7 +825,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer - mZenModeHelper.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenModeLocked("test", true); } verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, mZenModeHelper.TAG); @@ -2269,7 +2269,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // Artificially turn zen mode "on". Re-evaluating zen mode should cause it to turn back off // given that we don't have any zen rules active. mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - mZenModeHelper.evaluateZenMode("test", true); + mZenModeHelper.evaluateZenModeLocked("test", true); // Check that the change actually took: zen mode should be off now assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 5c3102d870d0..65e77dcd4ca9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -182,12 +182,12 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase { @Test public void testLaunchState() { - final ToIntFunction<Boolean> launchTemplate = doRelaunch -> { + final ToIntFunction<Runnable> launchTemplate = action -> { clearInvocations(mLaunchObserver); onActivityLaunched(mTopActivity); notifyTransitionStarting(mTopActivity); - if (doRelaunch) { - mActivityMetricsLogger.notifyActivityRelaunched(mTopActivity); + if (action != null) { + action.run(); } final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity); @@ -199,21 +199,27 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase { // Assume that the process is started (ActivityBuilder has mocked the returned value of // ATMS#getProcessController) but the activity has not attached process. mTopActivity.app = null; - assertWithMessage("Warm launch").that(launchTemplate.applyAsInt(false /* doRelaunch */)) + assertWithMessage("Warm launch").that(launchTemplate.applyAsInt(null)) .isEqualTo(WaitResult.LAUNCH_STATE_WARM); mTopActivity.app = app; mNewActivityCreated = false; - assertWithMessage("Hot launch").that(launchTemplate.applyAsInt(false /* doRelaunch */)) + assertWithMessage("Hot launch").that(launchTemplate.applyAsInt(null)) .isEqualTo(WaitResult.LAUNCH_STATE_HOT); - assertWithMessage("Relaunch").that(launchTemplate.applyAsInt(true /* doRelaunch */)) + assertWithMessage("Relaunch").that(launchTemplate.applyAsInt( + () -> mActivityMetricsLogger.notifyActivityRelaunched(mTopActivity))) .isEqualTo(WaitResult.LAUNCH_STATE_RELAUNCH); + assertWithMessage("Cold launch by restart").that(launchTemplate.applyAsInt( + () -> mActivityMetricsLogger.notifyBindApplication( + mTopActivity.info.applicationInfo))) + .isEqualTo(WaitResult.LAUNCH_STATE_COLD); + mTopActivity.app = null; mNewActivityCreated = true; doReturn(null).when(mAtm).getProcessController(app.mName, app.mUid); - assertWithMessage("Cold launch").that(launchTemplate.applyAsInt(false /* doRelaunch */)) + assertWithMessage("Cold launch").that(launchTemplate.applyAsInt(null)) .isEqualTo(WaitResult.LAUNCH_STATE_COLD); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java index 51a7e747afce..06033c7ebf75 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java @@ -20,7 +20,6 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP; -import static com.android.server.wm.LetterboxConfigurationPersister.LETTERBOX_CONFIGURATION_FILENAME; import android.annotation.NonNull; import android.annotation.Nullable; @@ -42,13 +41,26 @@ import org.junit.Test; import java.io.File; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.function.Supplier; +/** + * Tests for the {@link LetterboxConfigurationPersister} class. + * + * Build/Install/Run: + * atest WmTests:LetterboxConfigurationPersisterTest + */ @SmallTest @Presubmit public class LetterboxConfigurationPersisterTest { private static final long TIMEOUT = 2000L; // 2 secs + private static final int DEFAULT_REACHABILITY_TEST = -1; + private static final Supplier<Integer> DEFAULT_REACHABILITY_SUPPLIER_TEST = + () -> DEFAULT_REACHABILITY_TEST; + + private static final String LETTERBOX_CONFIGURATION_TEST_FILENAME = "letterbox_config_test"; + private LetterboxConfigurationPersister mLetterboxConfigurationPersister; private Context mContext; private PersisterQueue mPersisterQueue; @@ -62,7 +74,7 @@ public class LetterboxConfigurationPersisterTest { mConfigFolder = mContext.getFilesDir(); mPersisterQueue = new PersisterQueue(); mQueueState = new QueueState(); - mLetterboxConfigurationPersister = new LetterboxConfigurationPersister(mContext, + mLetterboxConfigurationPersister = new LetterboxConfigurationPersister( () -> mContext.getResources().getInteger( R.integer.config_letterboxDefaultPositionForHorizontalReachability), () -> mContext.getResources().getInteger( @@ -72,7 +84,8 @@ public class LetterboxConfigurationPersisterTest { () -> mContext.getResources().getInteger( R.integer.config_letterboxDefaultPositionForTabletopModeReachability ), - mConfigFolder, mPersisterQueue, mQueueState); + mConfigFolder, mPersisterQueue, mQueueState, + LETTERBOX_CONFIGURATION_TEST_FILENAME); mQueueListener = queueEmpty -> mQueueState.onItemAdded(); mPersisterQueue.addListener(mQueueListener); mLetterboxConfigurationPersister.start(); @@ -127,8 +140,10 @@ public class LetterboxConfigurationPersisterTest { public void test_whenUpdatedWithNewValues_valuesAreReadAfterRestart() { final PersisterQueue firstPersisterQueue = new PersisterQueue(); final LetterboxConfigurationPersister firstPersister = new LetterboxConfigurationPersister( - mContext, () -> -1, () -> -1, () -> -1, () -> -1, mContext.getFilesDir(), - firstPersisterQueue, mQueueState); + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + mContext.getFilesDir(), firstPersisterQueue, mQueueState, + LETTERBOX_CONFIGURATION_TEST_FILENAME); firstPersister.start(); firstPersister.setLetterboxPositionForHorizontalReachability(false, LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT); @@ -138,8 +153,10 @@ public class LetterboxConfigurationPersisterTest { stopPersisterSafe(firstPersisterQueue); final PersisterQueue secondPersisterQueue = new PersisterQueue(); final LetterboxConfigurationPersister secondPersister = new LetterboxConfigurationPersister( - mContext, () -> -1, () -> -1, () -> -1, () -> -1, mContext.getFilesDir(), - secondPersisterQueue, mQueueState); + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + mContext.getFilesDir(), secondPersisterQueue, mQueueState, + LETTERBOX_CONFIGURATION_TEST_FILENAME); secondPersister.start(); final int newPositionForHorizontalReachability = secondPersister.getLetterboxPositionForHorizontalReachability(false); @@ -156,37 +173,46 @@ public class LetterboxConfigurationPersisterTest { @Test public void test_whenUpdatedWithNewValuesAndDeleted_valuesAreDefaults() { - mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(false, + final PersisterQueue firstPersisterQueue = new PersisterQueue(); + final LetterboxConfigurationPersister firstPersister = new LetterboxConfigurationPersister( + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + mContext.getFilesDir(), firstPersisterQueue, mQueueState, + LETTERBOX_CONFIGURATION_TEST_FILENAME); + firstPersister.start(); + firstPersister.setLetterboxPositionForHorizontalReachability(false, LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT); - mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(false, + firstPersister.setLetterboxPositionForVerticalReachability(false, LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP); waitForCompletion(mPersisterQueue); final int newPositionForHorizontalReachability = - mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability( - false); + firstPersister.getLetterboxPositionForHorizontalReachability(false); final int newPositionForVerticalReachability = - mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(false); + firstPersister.getLetterboxPositionForVerticalReachability(false); Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT, newPositionForHorizontalReachability); Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP, newPositionForVerticalReachability); - deleteConfiguration(mLetterboxConfigurationPersister, mPersisterQueue); - waitForCompletion(mPersisterQueue); + deleteConfiguration(firstPersister, firstPersisterQueue); + waitForCompletion(firstPersisterQueue); + stopPersisterSafe(firstPersisterQueue); + + final PersisterQueue secondPersisterQueue = new PersisterQueue(); + final LetterboxConfigurationPersister secondPersister = new LetterboxConfigurationPersister( + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + DEFAULT_REACHABILITY_SUPPLIER_TEST, DEFAULT_REACHABILITY_SUPPLIER_TEST, + mContext.getFilesDir(), secondPersisterQueue, mQueueState, + LETTERBOX_CONFIGURATION_TEST_FILENAME); + secondPersister.start(); final int positionForHorizontalReachability = - mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability( - false); - final int defaultPositionForHorizontalReachability = - mContext.getResources().getInteger( - R.integer.config_letterboxDefaultPositionForHorizontalReachability); - Assert.assertEquals(defaultPositionForHorizontalReachability, - positionForHorizontalReachability); + secondPersister.getLetterboxPositionForHorizontalReachability(false); final int positionForVerticalReachability = - mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(false); - final int defaultPositionForVerticalReachability = - mContext.getResources().getInteger( - R.integer.config_letterboxDefaultPositionForVerticalReachability); - Assert.assertEquals(defaultPositionForVerticalReachability, - positionForVerticalReachability); + secondPersister.getLetterboxPositionForVerticalReachability(false); + Assert.assertEquals(DEFAULT_REACHABILITY_TEST, positionForHorizontalReachability); + Assert.assertEquals(DEFAULT_REACHABILITY_TEST, positionForVerticalReachability); + deleteConfiguration(secondPersister, secondPersisterQueue); + waitForCompletion(secondPersisterQueue); + stopPersisterSafe(secondPersisterQueue); } private void stopPersisterSafe(PersisterQueue persisterQueue) { @@ -222,7 +248,7 @@ public class LetterboxConfigurationPersisterTest { private void deleteConfiguration(LetterboxConfigurationPersister persister, PersisterQueue persisterQueue) { final AtomicFile fileToDelete = new AtomicFile( - new File(mConfigFolder, LETTERBOX_CONFIGURATION_FILENAME)); + new File(mConfigFolder, LETTERBOX_CONFIGURATION_TEST_FILENAME)); persisterQueue.addItem( new DeleteFileCommand(fileToDelete, mQueueState.andThen( s -> persister.useDefaultValue())), true); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index b02b774da86a..df0808f72c3f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -1315,6 +1315,26 @@ public class RecentTasksTest extends WindowTestsBase { assertTrue(info.supportsMultiWindow); } + @Test + public void testRemoveCompatibleRecentTask() { + final Task task1 = createTaskBuilder(".Task").setWindowingMode( + WINDOWING_MODE_FULLSCREEN).build(); + mRecentTasks.add(task1); + final Task task2 = createTaskBuilder(".Task").setWindowingMode( + WINDOWING_MODE_MULTI_WINDOW).build(); + mRecentTasks.add(task2); + assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, + true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size()); + + // Set windowing mode and ensure the same fullscreen task that created earlier is removed. + task2.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + mRecentTasks.removeCompatibleRecentTask(task2); + assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, + true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size()); + assertEquals(task2.mTaskId, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, + true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().get(0).taskId); + } + private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) { HardwareBuffer buffer = null; if (bufferSize != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java index abf21a57dd40..7eab06ac8b95 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java @@ -656,7 +656,7 @@ public class RootTaskTests extends WindowTestsBase { topSplitPrimary.getVisibility(null /* starting */)); // Make primary split root transient-hide. spyOn(splitPrimary.mTransitionController); - doReturn(true).when(splitPrimary.mTransitionController).isTransientHide( + doReturn(true).when(splitPrimary.mTransitionController).isTransientVisible( organizer.mPrimary); // The split root and its top become visible. assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 3908947804cd..d5afe3b2f078 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -27,6 +27,11 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_DISPLAY_SIZE; +import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; @@ -91,9 +96,12 @@ import android.compat.testing.PlatformCompatChangeRule; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.ScreenOrientation; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; +import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; @@ -2255,6 +2263,169 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testUserOverrideSplitScreenAspectRatioForLandscapeDisplay() { + final int displayWidth = 1600; + final int displayHeight = 1400; + setUpDisplaySizeWithApp(displayWidth, displayHeight); + + float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth); + + testUserOverrideAspectRatio(expectedAspectRatio, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN); + } + + @Test + public void testUserOverrideSplitScreenAspectRatioForPortraitDisplay() { + final int displayWidth = 1400; + final int displayHeight = 1600; + setUpDisplaySizeWithApp(displayWidth, displayHeight); + + float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight); + + testUserOverrideAspectRatio(expectedAspectRatio, USER_MIN_ASPECT_RATIO_SPLIT_SCREEN); + } + + @Test + public void testUserOverrideDisplaySizeAspectRatioForLandscapeDisplay() { + final int displayWidth = 1600; + final int displayHeight = 1400; + setUpDisplaySizeWithApp(displayWidth, displayHeight); + + float expectedAspectRatio = 1f * displayWidth / displayHeight; + + testUserOverrideAspectRatio(expectedAspectRatio, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE); + } + + @Test + public void testUserOverrideDisplaySizeAspectRatioForPortraitDisplay() { + final int displayWidth = 1400; + final int displayHeight = 1600; + setUpDisplaySizeWithApp(displayWidth, displayHeight); + + float expectedAspectRatio = 1f * displayHeight / displayWidth; + + testUserOverrideAspectRatio(expectedAspectRatio, USER_MIN_ASPECT_RATIO_DISPLAY_SIZE); + } + + @Test + public void testUserOverride32AspectRatioForPortraitDisplay() { + setUpDisplaySizeWithApp(/* dw */ 1400, /* dh */ 1600); + testUserOverrideAspectRatio(3 / 2f, USER_MIN_ASPECT_RATIO_3_2); + } + + @Test + public void testUserOverride32AspectRatioForLandscapeDisplay() { + setUpDisplaySizeWithApp(/* dw */ 1600, /* dh */ 1400); + testUserOverrideAspectRatio(3 / 2f, USER_MIN_ASPECT_RATIO_3_2); + } + + @Test + public void testUserOverride43AspectRatioForPortraitDisplay() { + setUpDisplaySizeWithApp(/* dw */ 1400, /* dh */ 1600); + testUserOverrideAspectRatio(4 / 3f, USER_MIN_ASPECT_RATIO_4_3); + } + + @Test + public void testUserOverride43AspectRatioForLandscapeDisplay() { + setUpDisplaySizeWithApp(/* dw */ 1600, /* dh */ 1400); + testUserOverrideAspectRatio(4 / 3f, USER_MIN_ASPECT_RATIO_4_3); + } + + @Test + public void testUserOverride169AspectRatioForPortraitDisplay() { + setUpDisplaySizeWithApp(/* dw */ 1800, /* dh */ 1500); + testUserOverrideAspectRatio(16 / 9f, USER_MIN_ASPECT_RATIO_16_9); + } + + @Test + public void testUserOverride169AspectRatioForLandscapeDisplay() { + setUpDisplaySizeWithApp(/* dw */ 1500, /* dh */ 1800); + testUserOverrideAspectRatio(16 / 9f, USER_MIN_ASPECT_RATIO_16_9); + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE}) + public void testUserOverrideAspectRatioOverSystemOverride() { + setUpDisplaySizeWithApp(/* dw */ 1600, /* dh */ 1400); + + testUserOverrideAspectRatio(false, + SCREEN_ORIENTATION_PORTRAIT, + 3 / 2f, + USER_MIN_ASPECT_RATIO_3_2, + true); + } + + @Test + public void testUserOverrideAspectRatioNotEnabled() { + setUpDisplaySizeWithApp(/* dw */ 1600, /* dh */ 1400); + + // App aspect ratio doesn't change + testUserOverrideAspectRatio(false, + SCREEN_ORIENTATION_PORTRAIT, + 1f * 1600 / 1400, + USER_MIN_ASPECT_RATIO_3_2, + false); + } + + private void testUserOverrideAspectRatio(float expectedAspectRatio, + @PackageManager.UserMinAspectRatio int aspectRatio) { + testUserOverrideAspectRatio(true, + SCREEN_ORIENTATION_PORTRAIT, + expectedAspectRatio, + aspectRatio, + true); + + testUserOverrideAspectRatio(false, + SCREEN_ORIENTATION_PORTRAIT, + expectedAspectRatio, + aspectRatio, + true); + + testUserOverrideAspectRatio(true, + SCREEN_ORIENTATION_LANDSCAPE, + expectedAspectRatio, + aspectRatio, + true); + + testUserOverrideAspectRatio(false, + SCREEN_ORIENTATION_LANDSCAPE, + expectedAspectRatio, + aspectRatio, + true); + } + + private void testUserOverrideAspectRatio(boolean isUnresizable, int screenOrientation, + float expectedAspectRatio, @PackageManager.UserMinAspectRatio int aspectRatio, + boolean enabled) { + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + activity.mWmService.mLetterboxConfiguration + .setUserAppAspectRatioSettingsOverrideEnabled(enabled); + // Set user aspect ratio override + final IPackageManager pm = mAtm.getPackageManager(); + try { + doReturn(aspectRatio).when(pm) + .getUserMinAspectRatio(activity.packageName, activity.mUserId); + } catch (RemoteException ignored) { + } + + prepareLimitedBounds(activity, screenOrientation, isUnresizable); + + final Rect afterBounds = activity.getBounds(); + final int width = afterBounds.width(); + final int height = afterBounds.height(); + final float afterAspectRatio = + (float) Math.max(width, height) / (float) Math.min(width, height); + + assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); + } + + @Test @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) public void testOverrideSplitScreenAspectRatioForUnresizablePortraitApps() { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index ed0c8ef489e5..e91fdde955ef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -61,6 +61,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -1425,6 +1426,15 @@ public class TransitionTests extends WindowTestsBase { // No need to wait for the activity in transient hide task. assertEquals(WindowContainer.SYNC_STATE_NONE, activity1.mSyncState); + // An active transient launch overrides idle state to avoid clearing power mode before the + // transition is finished. + spyOn(mRootWindowContainer.mTransitionController); + doAnswer(invocation -> controller.isTransientLaunch(invocation.getArgument(0))).when( + mRootWindowContainer.mTransitionController).isTransientLaunch(any()); + activity2.getTask().setResumedActivity(activity2, "test"); + activity2.idle = true; + assertFalse(mRootWindowContainer.allResumedActivitiesIdle()); + activity1.setVisibleRequested(false); activity2.setVisibleRequested(true); activity2.setVisible(true); @@ -1474,6 +1484,47 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testIsTransientVisible() { + final ActivityRecord appB = new ActivityBuilder(mAtm).setCreateTask(true) + .setVisible(false).build(); + final ActivityRecord recent = new ActivityBuilder(mAtm).setCreateTask(true) + .setVisible(false).build(); + final ActivityRecord appA = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final Task taskA = appA.getTask(); + final Task taskB = appB.getTask(); + final Task taskRecent = recent.getTask(); + registerTestTransitionPlayer(); + final TransitionController controller = mRootWindowContainer.mTransitionController; + final Transition transition = createTestTransition(TRANSIT_OPEN, controller); + controller.moveToCollecting(transition); + transition.collect(recent); + transition.collect(taskA); + transition.setTransientLaunch(recent, taskA); + taskRecent.moveToFront("move-recent-to-front"); + + // During collecting and playing, the recent is on top so it is visible naturally. + // While B needs isTransientVisible to keep visibility because it is occluded by recents. + assertFalse(controller.isTransientVisible(taskB)); + assertTrue(controller.isTransientVisible(taskA)); + assertFalse(controller.isTransientVisible(taskRecent)); + // Switch to playing state. + transition.onTransactionReady(transition.getSyncId(), mMockT); + assertTrue(controller.isTransientVisible(taskA)); + + // Switch to another task. For example, use gesture navigation to switch tasks. + taskB.moveToFront("move-b-to-front"); + // The previous app (taskA) should be paused first so it loses transient visible. Because + // visually it is taskA -> taskB, the pause -> resume order should be the same. + assertFalse(controller.isTransientVisible(taskA)); + // Keep the recent visible so there won't be 2 activities pausing at the same time. It is + // to avoid the latency to resume the current top, i.e. appB. + assertTrue(controller.isTransientVisible(taskRecent)); + // The recent is paused after the transient transition is finished. + controller.finishTransition(transition); + assertFalse(controller.isTransientVisible(taskRecent)); + } + + @Test public void testNotReadyPushPop() { final TransitionController controller = new TestTransitionController(mAtm); controller.setSyncEngine(mWm.mSyncEngine); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 3e7919305cbf..3703349b8d7e 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9400,6 +9400,39 @@ public class CarrierConfigManager { "missed_incoming_call_sms_pattern_string_array"; /** + * Indicate the satellite services supported per provider by a carrier. + * + * Key is the PLMN of a satellite provider. Value should be an integer array of supported + * services with the following value: + * <ul> + * <li>1 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VOICE}</li> + * <li>2 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_DATA}</li> + * <li>3 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_SMS}</li> + * <li>4 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VIDEO}</li> + * <li>5 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_EMERGENCY}</li> + * </ul> + * <p> + * If this carrier config is not present, the overlay config + * {@code config_satellite_services_supported_by_providers} will be used. If the carrier config + * is present, the supported satellite services will be identified as follows: + * <ul> + * <li>For the PLMN that exists in both provider supported satellite services and carrier + * supported satellite services, the supported services will be the intersection of the two + * sets.</li> + * <li>For the PLMN that is present in provider supported satellite services but not in carrier + * supported satellite services, the provider supported satellite services will be used.</li> + * <li>For the PLMN that is present in carrier supported satellite services but not in provider + * supported satellite services, the PLMN will be ignored.</li> + * </ul> + * + * This config is empty by default. + * + * @hide + */ + public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = + "carrier_supported_satellite_services_per_provider_bundle"; + + /** * Indicating whether DUN APN should be disabled when the device is roaming. In that case, * the default APN (i.e. internet) will be used for tethering. * @@ -9621,6 +9654,7 @@ public class CarrierConfigManager { * * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED */ public static final String KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = @@ -10404,6 +10438,9 @@ public class CarrierConfigManager { }); sDefaults.putBoolean(KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, false); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); + sDefaults.putPersistableBundle( + KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + PersistableBundle.EMPTY); sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false); sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, ""); sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false); diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 182d2fcbec67..f012ab56d94d 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -203,6 +203,12 @@ public final class NetworkRegistrationInfo implements Parcelable { */ public static final int SERVICE_TYPE_EMERGENCY = 5; + /** @hide */ + public static final int FIRST_SERVICE_TYPE = SERVICE_TYPE_VOICE; + + /** @hide */ + public static final int LAST_SERVICE_TYPE = SERVICE_TYPE_EMERGENCY; + @Domain private final int mDomain; @@ -240,7 +246,7 @@ public final class NetworkRegistrationInfo implements Parcelable { private final boolean mEmergencyOnly; @ServiceType - private final ArrayList<Integer> mAvailableServices; + private ArrayList<Integer> mAvailableServices; @Nullable private CellIdentity mCellIdentity; @@ -604,6 +610,16 @@ public final class NetworkRegistrationInfo implements Parcelable { } /** + * Set available service types. + * + * @param availableServices The list of available services for this network. + * @hide + */ + public void setAvailableServices(@NonNull @ServiceType List<Integer> availableServices) { + mAvailableServices = new ArrayList<>(availableServices); + } + + /** * @return The access network technology {@link NetworkType}. */ public @NetworkType int getAccessNetworkTechnology() { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 2a6099a18fab..340e4ab132ca 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -17608,6 +17608,16 @@ public class TelephonyManager { public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP = 15; /** + * Purchase premium capability failed because the user disabled the feature. + * Subsequent attempts will be throttled for the amount of time specified by + * {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG} + * and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}. + * @hide + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED = 16; + + /** * Results of the purchase premium capability request. * @hide */ @@ -17626,7 +17636,8 @@ public class TelephonyManager { PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE, PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED, PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION, - PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}) + PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP, + PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED}) public @interface PurchasePremiumCapabilityResult {} /** diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt new file mode 100644 index 000000000000..0417f9dbb4bf --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.activityembedding + +import android.platform.test.annotations.Presubmit +import android.tools.common.datatypes.Rect +import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.common.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test launching a secondary Activity into Picture-In-Picture mode. + * + * Setup: Start from a split A|B. + * Transition: B enters PIP, observe the window shrink to the bottom right corner on screen. + * + * To run this test: `atest FlickerTests:SecondaryActivityEnterPipTest` + * + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class SecondaryActivityEnterPipTest (flicker: LegacyFlickerTest) : + ActivityEmbeddingTestBase(flicker) { + override val transition: FlickerBuilder.() -> Unit = { + setup { + tapl.setExpectedRotationCheckEnabled(false) + testApp.launchViaIntent(wmHelper) + testApp.launchSecondaryActivity(wmHelper) + startDisplayBounds = + wmHelper.currentState.layerState.physicalDisplayBounds + ?: error("Can't get display bounds") + } + transitions { + testApp.secondaryActivityEnterPip(wmHelper) + } + teardown { + tapl.goHome() + testApp.exit(wmHelper) + } + } + + /** + * Main and secondary activity start from a split each taking half of the screen. + */ + @Presubmit + @Test + fun layersStartFromEqualSplit() { + flicker.assertLayersStart { + val leftLayerRegion = + visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + val rightLayerRegion = + visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) + // Compare dimensions of two splits, given we're using default split attributes, + // both activities take up the same visible size on the display. + check { "height" } + .that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height) + check { "width" } + .that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width) + leftLayerRegion.notOverlaps(rightLayerRegion.region) + leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds) + } + flicker.assertLayersEnd { + visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + .coversExactly(startDisplayBounds) + } + } + + /** + * Main Activity is visible throughout the transition and becomes fullscreen. + */ + @Presubmit + @Test + fun mainActivityWindowBecomesFullScreen() { + flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) } + flicker.assertWmEnd { + visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + .coversExactly(startDisplayBounds) + } + } + + /** + * Main Activity is visible throughout the transition and becomes fullscreen. + */ + @Presubmit + @Test + fun mainActivityLayerBecomesFullScreen() { + flicker.assertLayers { + isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + .then() + .isVisible(TRANSITION_SNAPSHOT) + .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + .then() + .isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + } + flicker.assertLayersEnd { + visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + .coversExactly(startDisplayBounds) + } + } + + /** + * Secondary Activity is visible throughout the transition and shrinks to the bottom right + * corner. + */ + @Presubmit + @Test + fun secondaryWindowShrinks() { + flicker.assertWm { + isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) + } + flicker.assertWmEnd { + val pipWindowRegion = + visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) + check{"height"} + .that(pipWindowRegion.region.height) + .isLower(startDisplayBounds.height / 2) + check{"width"} + .that(pipWindowRegion.region.width).isLower(startDisplayBounds.width) + } + } + + /** + * During the transition Secondary Activity shrinks to the bottom right corner. + */ + @Presubmit + @Test + fun secondaryLayerShrinks() { + flicker.assertLayers { + val pipLayerList = layers { + ComponentNameMatcher.PIP_CONTENT_OVERLAY.layerMatchesAnyOf(it) && it.isVisible + } + pipLayerList.zipWithNext { previous, current -> + // TODO(b/290987990): Add checks for visibleRegion. + current.screenBounds.isToTheRightBottom(previous.screenBounds.region, 3) + current.screenBounds.notBiggerThan(previous.screenBounds.region) + } + } + flicker.assertLayersEnd { + val pipRegion = visibleRegion( + ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) + check { "height" } + .that(pipRegion.region.height) + .isLower(startDisplayBounds.height / 2) + check { "width" } + .that(pipRegion.region.width).isLower(startDisplayBounds.width) + } + } + + companion object { + /** {@inheritDoc} */ + private var startDisplayBounds = Rect.EMPTY + /** + * Creates the test configurations. + * + * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams() = LegacyFlickerTestFactory.nonRotationTests() + } +}
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt index eac88132d410..ade1491fa17b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt @@ -113,6 +113,21 @@ constructor( .waitForAndVerify() } + fun secondaryActivityEnterPip(wmHelper: WindowManagerStateHelper) { + val pipButton = + uiDevice.wait( + Until.findObject(By.res(getPackage(), "secondary_enter_pip_button")), + FIND_TIMEOUT + ) + require(pipButton != null) { "Can't find enter pip button on screen." } + pipButton.click() + wmHelper + .StateSyncBuilder() + .withAppTransitionIdle() + .withPipShown() + .waitForAndVerify() + } + /** * Clicks the button to launch a secondary activity with alwaysExpand enabled, which will launch * a fullscreen window on top of the visible region. diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml index 68ae806f3c8b..ff9799a1c710 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -102,6 +102,24 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + <activity android:name=".LaunchTransparentActivity" + android:resizeableActivity="false" + android:screenOrientation="portrait" + android:theme="@android:style/Theme" + android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchTransparentActivity" + android:label="LaunchTransparentActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".TransparentActivity" + android:theme="@style/TransparentTheme" + android:taskAffinity="com.android.server.wm.flicker.testapp.TransparentActivity" + android:label="TransparentActivity" + android:exported="false"> + </activity> <activity android:name=".LaunchNewActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity" android:theme="@style/CutoutShortEdges" @@ -206,6 +224,7 @@ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" + android:supportsPictureInPicture="true" android:exported="false"/> <activity android:name=".ActivityEmbeddingThirdActivity" diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml index 67314463161d..135140aa2377 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml @@ -35,4 +35,10 @@ android:onClick="launchThirdActivity" android:text="Launch a third activity" /> + <Button + android:id="@+id/secondary_enter_pip_button" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:text="Enter pip" /> + </LinearLayout>
\ No newline at end of file diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml new file mode 100644 index 000000000000..0730ded66ce4 --- /dev/null +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + +</FrameLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml new file mode 100644 index 000000000000..ff4ead95f16e --- /dev/null +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@android:color/black"> + + <Button + android:id="@+id/button_launch_transparent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" + android:text="Launch Transparent" /> + <Button + android:id="@+id/button_request_permission" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" + android:text="Request Permission" /> +</LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml index 1d21fd56a487..e51ed29adebf 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml @@ -43,6 +43,13 @@ <item name="android:windowSoftInputMode">stateUnchanged</item> </style> + <style name="TransparentTheme" parent="@android:style/Theme.DeviceDefault"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:backgroundDimEnabled">false</item> + </style> + <style name="no_starting_window" parent="@android:style/Theme.DeviceDefault"> <item name="android:windowDisablePreview">true</item> </style> diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java index dc21027bc99c..ee087ef9be2c 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java @@ -18,6 +18,7 @@ package com.android.server.wm.flicker.testapp; import android.app.Activity; import android.content.Intent; +import android.app.PictureInPictureParams; import android.graphics.Color; import android.os.Bundle; import android.view.View; @@ -40,6 +41,16 @@ public class ActivityEmbeddingSecondaryActivity extends Activity { finish(); } }); + findViewById(R.id.secondary_enter_pip_button).setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + PictureInPictureParams.Builder picInPicParamsBuilder = + new PictureInPictureParams.Builder(); + enterPictureInPictureMode(picInPicParamsBuilder.build()); + } + } + ); } public void launchThirdActivity(View view) { diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java index 95c86acb9ee9..2795a6c43015 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java @@ -73,6 +73,18 @@ public class ActivityOptions { FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity"); } + public static class TransparentActivity { + public static final String LABEL = "TransparentActivity"; + public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, + FLICKER_APP_PACKAGE + ".TransparentActivity"); + } + + public static class LaunchTransparentActivity { + public static final String LABEL = "LaunchTransparentActivity"; + public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, + FLICKER_APP_PACKAGE + ".LaunchTransparentActivity"); + } + public static class DialogThemedActivity { public static final String LABEL = "DialogThemedActivity"; public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchTransparentActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchTransparentActivity.java new file mode 100644 index 000000000000..7c161fd8e611 --- /dev/null +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchTransparentActivity.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.testapp; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class LaunchTransparentActivity extends Activity { + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.activity_transparent_launch); + findViewById(R.id.button_launch_transparent) + .setOnClickListener(v -> launchTransparentActivity()); + } + + private void launchTransparentActivity() { + startActivity(new Intent(this, TransparentActivity.class)); + } +} diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransparentActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransparentActivity.java new file mode 100644 index 000000000000..1bac8bdb003a --- /dev/null +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransparentActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.testapp; + +import android.app.Activity; +import android.os.Bundle; + +public class TransparentActivity extends Activity { + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.activity_transparent); + } +} diff --git a/tests/Internal/src/android/service/wallpaper/OWNERS b/tests/Internal/src/android/service/wallpaper/OWNERS new file mode 100644 index 000000000000..5a26d0e1f62b --- /dev/null +++ b/tests/Internal/src/android/service/wallpaper/OWNERS @@ -0,0 +1,4 @@ +dupin@google.com +santie@google.com +pomini@google.com +poultney@google.com
\ No newline at end of file diff --git a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java index 153ca79e346b..0c5e8d481131 100644 --- a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java +++ b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java @@ -85,4 +85,17 @@ public class WallpaperServiceTest { assertEquals("onAmbientModeChanged should have been called", 2, zoomChangedCount[0]); } + @Test + public void testNotifyColorsOfDestroyedEngine_doesntCrash() { + WallpaperService service = new WallpaperService() { + @Override + public Engine onCreateEngine() { + return new Engine(); + } + }; + WallpaperService.Engine engine = service.onCreateEngine(); + engine.detach(); + + engine.notifyColorsChanged(); + } } diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index edd6dd3468ef..82e40b1eee6b 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -32,6 +32,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; /** * This is a wrapper around {@link TestLooperManager} to make it easier to manage @@ -55,7 +56,6 @@ public class TestableLooper { private MessageHandler mMessageHandler; private Handler mHandler; - private Runnable mEmptyMessage; private TestLooperManager mQueueWrapper; static { @@ -121,8 +121,12 @@ public class TestableLooper { * @param num Number of messages to parse */ public int processMessages(int num) { + return processMessagesInternal(num, null); + } + + private int processMessagesInternal(int num, Runnable barrierRunnable) { for (int i = 0; i < num; i++) { - if (!parseMessageInt()) { + if (!processSingleMessage(barrierRunnable)) { return i + 1; } } @@ -130,6 +134,27 @@ public class TestableLooper { } /** + * Process up to a certain number of messages, not blocking if the queue has less messages than + * that + * @param num the maximum number of messages to process + * @return the number of messages processed. This will be at most {@code num}. + */ + + public int processMessagesNonBlocking(int num) { + final AtomicBoolean reachedBarrier = new AtomicBoolean(false); + Runnable barrierRunnable = () -> { + reachedBarrier.set(true); + }; + mHandler.post(barrierRunnable); + waitForMessage(mQueueWrapper, mHandler, barrierRunnable); + try { + return processMessagesInternal(num, barrierRunnable) + (reachedBarrier.get() ? -1 : 0); + } finally { + mHandler.removeCallbacks(barrierRunnable); + } + } + + /** * Process messages in the queue until no more are found. */ public void processAllMessages() { @@ -165,19 +190,20 @@ public class TestableLooper { private int processQueuedMessages() { int count = 0; - mEmptyMessage = () -> { }; - mHandler.post(mEmptyMessage); - waitForMessage(mQueueWrapper, mHandler, mEmptyMessage); - while (parseMessageInt()) count++; + Runnable barrierRunnable = () -> { }; + mHandler.post(barrierRunnable); + waitForMessage(mQueueWrapper, mHandler, barrierRunnable); + while (processSingleMessage(barrierRunnable)) count++; return count; } - private boolean parseMessageInt() { + private boolean processSingleMessage(Runnable barrierRunnable) { try { Message result = mQueueWrapper.next(); if (result != null) { // This is a break message. - if (result.getCallback() == mEmptyMessage) { + if (result.getCallback() == barrierRunnable) { + mQueueWrapper.execute(result); mQueueWrapper.recycle(result); return false; } diff --git a/tests/testables/tests/src/android/testing/TestableLooperTest.java b/tests/testables/tests/src/android/testing/TestableLooperTest.java index 0f491b86626c..a02eb6b176dc 100644 --- a/tests/testables/tests/src/android/testing/TestableLooperTest.java +++ b/tests/testables/tests/src/android/testing/TestableLooperTest.java @@ -27,12 +27,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; - import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -40,6 +34,11 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.TestableLooper.MessageHandler; import android.testing.TestableLooper.RunWithLooper; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; + @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -240,4 +239,33 @@ public class TestableLooperTest { inOrder.verify(handler).dispatchMessage(messageC); } + @Test + public void testProcessMessagesNonBlocking_onlyArgNumber() { + Handler h = new Handler(mTestableLooper.getLooper()); + Runnable r = mock(Runnable.class); + + h.post(r); + h.post(r); + h.post(r); + + int processed = mTestableLooper.processMessagesNonBlocking(2); + + verify(r, times(2)).run(); + assertEquals(2, processed); + } + + @Test + public void testProcessMessagesNonBlocking_lessMessagesThanArg() { + Handler h = new Handler(mTestableLooper.getLooper()); + Runnable r = mock(Runnable.class); + + h.post(r); + h.post(r); + h.post(r); + + int processed = mTestableLooper.processMessagesNonBlocking(5); + + verify(r, times(3)).run(); + assertEquals(3, processed); + } } |