diff options
966 files changed, 16375 insertions, 8349 deletions
@@ -30,8 +30,11 @@ per-file */TEST_MAPPING = * # Support bulk translation updates per-file */res*/values*/*.xml = byi@google.com, delphij@google.com +per-file **.bp,**.mk = hansson@google.com per-file *.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} per-file Android.mk = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} per-file framework-jarjar-rules.txt = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS + +per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS diff --git a/ZYGOTE_OWNERS b/ZYGOTE_OWNERS index 90a185b79b52..f6d15e03a892 100644 --- a/ZYGOTE_OWNERS +++ b/ZYGOTE_OWNERS @@ -1,4 +1,3 @@ -calin@google.com chriswailes@google.com maco@google.com narayan@google.com diff --git a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt b/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt index fabf8892b544..9482591c65b5 100644 --- a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt +++ b/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt @@ -33,7 +33,6 @@ import androidx.test.filters.LargeTest import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.After -import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule @@ -132,8 +131,7 @@ class MotionPredictorBenchmark { predictor.record(moveEvent) val predictionTime = eventTime + eventInterval val predicted = predictor.predict(predictionTime.toNanos()) - assertEquals(1, predicted.size) - assertTrue(predicted[0].eventTime <= (predictionTime + offset).toMillis()) + assertTrue(predicted.eventTime <= (predictionTime + offset).toMillis()) } } diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java index 2e44d82ca428..e9c6c1ae0c87 100644 --- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java +++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java @@ -76,6 +76,7 @@ public class ImePerfTest extends ImePerfTestBase implements ManualBenchmarkState.CustomizedIterationListener { private static final String TAG = ImePerfTest.class.getSimpleName(); private static final long ANIMATION_NOT_STARTED = -1; + private static final int WAIT_PROCESS_KILL_TIMEOUT_MS = 2000; @Rule public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); @@ -248,19 +249,18 @@ public class ImePerfTest extends ImePerfTestBase boolean shouldRetry = false; while (shouldRetry || state.keepRunning(measuredTimeNs)) { shouldRetry = false; - killBaselineIme(); + killBaselineImeSync(); try (ImeSession imeSession = new ImeSession(BaselineIme.getName( getInstrumentation().getContext()))) { + if (!mIsTraceStarted) { + startAsyncAtrace(); + } final AtomicReference<CountDownLatch> latchStart = new AtomicReference<>(); final Activity activity = getActivityWithFocus(); setImeListener(activity, latchStart, null /* latchEnd */); latchStart.set(new CountDownLatch(1)); - if (!mIsTraceStarted) { - startAsyncAtrace(); - } - final WindowInsetsController controller = activity.getWindow().getDecorView().getWindowInsetsController(); AtomicLong startTime = new AtomicLong(); @@ -270,6 +270,7 @@ public class ImePerfTest extends ImePerfTestBase }); measuredTimeNs = waitForAnimationStart(latchStart, startTime); + stopAsyncAtraceAndDumpTraces(); if (measuredTimeNs == ANIMATION_NOT_STARTED) { // Animation didn't start within timeout, @@ -285,7 +286,7 @@ public class ImePerfTest extends ImePerfTestBase addResultToState(state); } - private void killBaselineIme() { + private void killBaselineImeSync() { // pidof returns a space separated list of numeric PIDs. String result = SystemUtil.runShellCommand( "pidof com.android.perftests.inputmethod:BaselineIME"); @@ -294,7 +295,13 @@ public class ImePerfTest extends ImePerfTestBase if (TextUtils.isEmpty(pid)) { continue; } - Process.killProcess(Integer.parseInt(pid)); + final int pidToKill = Integer.parseInt(pid); + Process.killProcess(pidToKill); + try { + // Wait kill IME process being settled down. + Process.waitForProcessDeath(pidToKill, WAIT_PROCESS_KILL_TIMEOUT_MS); + } catch (Exception e) { + } } } @@ -381,7 +388,7 @@ public class ImePerfTest extends ImePerfTestBase } } finally { if (mIsTraceStarted) { - stopAsyncAtrace(); + stopAsyncAtraceAndDumpTraces(); } } mActivityRule.finishActivity(); @@ -488,7 +495,7 @@ public class ImePerfTest extends ImePerfTestBase startAsyncAtrace("wm view"); } - private void stopAsyncAtrace() { + private void stopAsyncAtraceAndDumpTraces() { if (!mIsTraceStarted) { return; } @@ -504,6 +511,14 @@ public class ImePerfTest extends ImePerfTestBase } } + private void stopAsyncAtrace() { + if (!mIsTraceStarted) { + return; + } + mIsTraceStarted = false; + getUiAutomation().executeShellCommand("atrace --async_stop"); + } + @Override public void onStart(int iteration) { // Do not capture trace when profiling because the result will be much slower. diff --git a/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java b/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java index e31162f37cf8..c00c8d550885 100644 --- a/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java +++ b/apct-tests/perftests/settingsprovider/src/android/provider/SettingsProviderPerfTest.java @@ -39,6 +39,7 @@ public final class SettingsProviderPerfTest { private static final String NAMESPACE = "test@namespace"; private static final String SETTING_NAME1 = "test:setting1"; private static final String SETTING_NAME2 = "test-setting2"; + private static final String UNSET_SETTING = "test_unset_setting"; private final ContentResolver mContentResolver; @@ -93,6 +94,14 @@ public final class SettingsProviderPerfTest { } @Test + public void testSettingsValueConsecutiveReadUnset() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Settings.Secure.getString(mContentResolver, UNSET_SETTING); + } + } + + @Test public void testSettingsNamespaceConsecutiveRead() { final List<String> names = new ArrayList<>(); names.add(SETTING_NAME1); diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java index ca5913701d3b..804baf4e6504 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java @@ -73,7 +73,7 @@ public class WindowPerfTestBase { } public static void startAsyncAtrace(String tags) { - getUiAutomation().executeShellCommand("atrace -b 32768 --async_start " + tags); + getUiAutomation().executeShellCommand("atrace --async_start -b 32768 -c " + tags); // Avoid atrace isn't ready immediately. SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); } diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 4caaa09f6a31..5de117261085 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -79,6 +79,9 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.provider.DeviceConfig; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.telephony.emergency.EmergencyNumber; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -146,15 +149,17 @@ import java.util.stream.Collectors; label="deep"; STATE_ACTIVE [ - label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon", + label="STATE_ACTIVE\nScreen on OR charging OR alarm going off soon\n" + + "OR active emergency call", color=black,shape=diamond ] STATE_INACTIVE [ - label="STATE_INACTIVE\nScreen off AND Not charging",color=black,shape=diamond + label="STATE_INACTIVE\nScreen off AND not charging AND no active emergency call", + color=black,shape=diamond ] STATE_QUICK_DOZE_DELAY [ label="STATE_QUICK_DOZE_DELAY\n" - + "Screen off AND Not charging\n" + + "Screen off AND not charging AND no active emergency call\n" + "Location, motion detection, and significant motion monitoring turned off", color=black,shape=diamond ] @@ -237,11 +242,12 @@ import java.util.stream.Collectors; label="light" LIGHT_STATE_ACTIVE [ - label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon", + label="LIGHT_STATE_ACTIVE\n" + + "Screen on OR charging OR alarm going off soon OR active emergency call", color=black,shape=diamond ] LIGHT_STATE_INACTIVE [ - label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging", + label="LIGHT_STATE_INACTIVE\nScreen off AND not charging AND no active emergency call", color=black,shape=diamond ] LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=red,shape=box] @@ -411,6 +417,7 @@ public class DeviceIdleController extends SystemService private static final int ACTIVE_REASON_FROM_BINDER_CALL = 5; private static final int ACTIVE_REASON_FORCED = 6; private static final int ACTIVE_REASON_ALARM = 7; + private static final int ACTIVE_REASON_EMERGENCY_CALL = 8; @VisibleForTesting static final int SET_IDLE_FACTOR_RESULT_UNINIT = -1; @VisibleForTesting @@ -765,6 +772,8 @@ public class DeviceIdleController extends SystemService } }; + private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener(); + /** Post stationary status only to this listener. */ private void postStationaryStatus(DeviceIdleInternal.StationaryListener listener) { mHandler.obtainMessage(MSG_REPORT_STATIONARY_STATUS, listener).sendToTarget(); @@ -2323,6 +2332,39 @@ public class DeviceIdleController extends SystemService } } + private class EmergencyCallListener extends TelephonyCallback implements + TelephonyCallback.OutgoingEmergencyCallListener, + TelephonyCallback.CallStateListener { + private volatile boolean mIsEmergencyCallActive; + + @Override + public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber, + int subscriptionId) { + mIsEmergencyCallActive = true; + if (DEBUG) Slog.d(TAG, "onOutgoingEmergencyCall(): subId = " + subscriptionId); + synchronized (DeviceIdleController.this) { + mActiveReason = ACTIVE_REASON_EMERGENCY_CALL; + becomeActiveLocked("emergency call", Process.myUid()); + } + } + + @Override + public void onCallStateChanged(int state) { + if (DEBUG) Slog.d(TAG, "onCallStateChanged(): state is " + state); + // An emergency call just finished + if (state == TelephonyManager.CALL_STATE_IDLE && mIsEmergencyCallActive) { + mIsEmergencyCallActive = false; + synchronized (DeviceIdleController.this) { + becomeInactiveIfAppropriateLocked(); + } + } + } + + boolean isEmergencyCallActive() { + return mIsEmergencyCallActive; + } + } + static class Injector { private final Context mContext; private ConnectivityManager mConnectivityManager; @@ -2406,6 +2448,10 @@ public class DeviceIdleController extends SystemService return mContext.getSystemService(SensorManager.class); } + TelephonyManager getTelephonyManager() { + return mContext.getSystemService(TelephonyManager.class); + } + ConstraintController getConstraintController(Handler handler, DeviceIdleInternal localService) { if (mContext.getPackageManager() @@ -2634,6 +2680,9 @@ public class DeviceIdleController extends SystemService mLocalActivityTaskManager.registerScreenObserver(mScreenObserver); + mInjector.getTelephonyManager().registerTelephonyCallback( + JobSchedulerBackgroundThread.getExecutor(), mEmergencyCallListener); + passWhiteListsToForceAppStandbyTrackerLocked(); updateInteractivityLocked(); } @@ -3435,6 +3484,7 @@ public class DeviceIdleController extends SystemService final boolean isScreenBlockingInactive = mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked); + final boolean isEmergencyCallActive = mEmergencyCallListener.isEmergencyCallActive(); if (DEBUG) { Slog.d(TAG, "becomeInactiveIfAppropriateLocked():" + " isScreenBlockingInactive=" + isScreenBlockingInactive @@ -3442,10 +3492,11 @@ public class DeviceIdleController extends SystemService + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK + ", mScreenLocked=" + mScreenLocked + ")" + " mCharging=" + mCharging + + " emergencyCall=" + isEmergencyCallActive + " mForceIdle=" + mForceIdle ); } - if (!mForceIdle && (mCharging || isScreenBlockingInactive)) { + if (!mForceIdle && (mCharging || isScreenBlockingInactive || isEmergencyCallActive)) { return; } // Become inactive and determine if we will ultimately go idle. @@ -3568,6 +3619,17 @@ public class DeviceIdleController extends SystemService } EventLogTags.writeDeviceIdleLightStep(); + if (mEmergencyCallListener.isEmergencyCallActive()) { + // The emergency call should have raised the state to ACTIVE and kept it there, + // so this method shouldn't be called. Don't proceed further. + Slog.wtf(TAG, "stepLightIdleStateLocked called when emergency call is active"); + if (mLightState != LIGHT_STATE_ACTIVE) { + mActiveReason = ACTIVE_REASON_EMERGENCY_CALL; + becomeActiveLocked("emergency", Process.myUid()); + } + return; + } + switch (mLightState) { case LIGHT_STATE_INACTIVE: mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET; @@ -3650,6 +3712,17 @@ public class DeviceIdleController extends SystemService if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState); EventLogTags.writeDeviceIdleStep(); + if (mEmergencyCallListener.isEmergencyCallActive()) { + // The emergency call should have raised the state to ACTIVE and kept it there, + // so this method shouldn't be called. Don't proceed further. + Slog.wtf(TAG, "stepIdleStateLocked called when emergency call is active"); + if (mState != STATE_ACTIVE) { + mActiveReason = ACTIVE_REASON_EMERGENCY_CALL; + becomeActiveLocked("emergency", Process.myUid()); + } + return; + } + if (isUpcomingAlarmClock()) { // Whoops, there is an upcoming alarm. We don't actually want to go idle. if (mState != STATE_ACTIVE) { @@ -3984,6 +4057,11 @@ public class DeviceIdleController extends SystemService } } + @VisibleForTesting + boolean isEmergencyCallActive() { + return mEmergencyCallListener.isEmergencyCallActive(); + } + @GuardedBy("this") boolean isOpsInactiveLocked() { return mActiveIdleOpCount <= 0 && !mJobsActive && !mAlarmsActive; @@ -5199,6 +5277,8 @@ public class DeviceIdleController extends SystemService pw.print(" mScreenLocked="); pw.println(mScreenLocked); pw.print(" mNetworkConnected="); pw.println(mNetworkConnected); pw.print(" mCharging="); pw.println(mCharging); + pw.print(" activeEmergencyCall="); + pw.println(mEmergencyCallListener.isEmergencyCallActive()); if (mConstraints.size() != 0) { pw.println(" mConstraints={"); for (int i = 0; i < mConstraints.size(); i++) { diff --git a/core/api/current.txt b/core/api/current.txt index 0536947ac07b..1464c5b5058b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -375,7 +375,7 @@ package android { public static final class R.attr { ctor public R.attr(); field public static final int absListViewStyle = 16842858; // 0x101006a - field public static final int accessibilityDataPrivate; + field public static final int accessibilityDataSensitive; field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 field public static final int accessibilityFlags = 16843652; // 0x1010384 @@ -4492,8 +4492,8 @@ package android.app { method public void openOptionsMenu(); method public void overrideActivityTransition(int, @AnimRes int, @AnimRes int); method public void overrideActivityTransition(int, @AnimRes int, @AnimRes int, @ColorInt int); - method public void overridePendingTransition(int, int); - method public void overridePendingTransition(int, int, int); + method @Deprecated public void overridePendingTransition(int, int); + method @Deprecated public void overridePendingTransition(int, int, int); method public void postponeEnterTransition(); method public void recreate(); method public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks); @@ -10333,7 +10333,7 @@ package android.content { field public static final int BIND_AUTO_CREATE = 1; // 0x1 field public static final int BIND_DEBUG_UNBIND = 2; // 0x2 field public static final int BIND_EXTERNAL_SERVICE = -2147483648; // 0x80000000 - field public static final long BIND_EXTERNAL_SERVICE_LONG = -9223372036854775808L; // 0x8000000000000000L + field public static final long BIND_EXTERNAL_SERVICE_LONG = 4611686018427387904L; // 0x4000000000000000L field public static final int BIND_IMPORTANT = 64; // 0x40 field public static final int BIND_INCLUDE_CAPABILITIES = 4096; // 0x1000 field public static final int BIND_NOT_FOREGROUND = 4; // 0x4 @@ -10441,7 +10441,6 @@ package android.content { } public static final class Context.BindServiceFlags { - method public long getValue(); method @NonNull public static android.content.Context.BindServiceFlags of(long); } @@ -13594,12 +13593,11 @@ package android.credentials { } public static final class CreateCredentialRequest.Builder { - ctor public CreateCredentialRequest.Builder(@NonNull android.os.Bundle, @NonNull android.os.Bundle); + ctor public CreateCredentialRequest.Builder(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle); method @NonNull public android.credentials.CreateCredentialRequest build(); method @NonNull public android.credentials.CreateCredentialRequest.Builder setAlwaysSendAppInfoToProvider(boolean); method @NonNull public android.credentials.CreateCredentialRequest.Builder setIsSystemProviderRequired(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN) public android.credentials.CreateCredentialRequest.Builder setOrigin(@NonNull String); - method @NonNull public android.credentials.CreateCredentialRequest.Builder setType(@NonNull String); } public final class CreateCredentialResponse implements android.os.Parcelable { @@ -19594,7 +19592,7 @@ package android.hardware.display { public final class VirtualDisplayConfig implements android.os.Parcelable { method public int describeContents(); method public int getDensityDpi(); - method @NonNull public java.util.List<java.lang.String> getDisplayCategories(); + method @NonNull public java.util.Set<java.lang.String> getDisplayCategories(); method public int getFlags(); method public int getHeight(); method @NonNull public String getName(); @@ -19609,7 +19607,7 @@ package android.hardware.display { ctor public VirtualDisplayConfig.Builder(@NonNull String, @IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder addDisplayCategory(@NonNull String); method @NonNull public android.hardware.display.VirtualDisplayConfig build(); - method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCategories(@NonNull java.util.List<java.lang.String>); + method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCategories(@NonNull java.util.Set<java.lang.String>); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setFlags(int); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setRequestedRefreshRate(@FloatRange(from=0.0f) float); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setSurface(@Nullable android.view.Surface); @@ -20389,7 +20387,7 @@ package android.location { public final class GnssCapabilities implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.location.GnssSignalType> getGnssSignalTypes(); - method public boolean hasAccumulatedDeltaRange(); + method public int hasAccumulatedDeltaRange(); method public boolean hasAntennaInfo(); method public boolean hasGeofencing(); method @Deprecated public boolean hasGnssAntennaInfo(); @@ -20415,8 +20413,10 @@ package android.location { method public boolean hasSatellitePvt(); method public boolean hasScheduling(); method public boolean hasSingleShotFix(); - method public boolean isAccumulatedDeltaRangeCapabilityKnown(); method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CAPABILITY_SUPPORTED = 1; // 0x1 + field public static final int CAPABILITY_UNKNOWN = 0; // 0x0 + field public static final int CAPABILITY_UNSUPPORTED = 2; // 0x2 field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR; } @@ -20424,9 +20424,8 @@ package android.location { ctor public GnssCapabilities.Builder(); ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities); method @NonNull public android.location.GnssCapabilities build(); - method @NonNull public android.location.GnssCapabilities.Builder clearIsAccumulatedDeltaRangeCapabilityKnown(); method @NonNull public android.location.GnssCapabilities.Builder setGnssSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>); - method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(int); method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean); method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean); method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean); @@ -33834,6 +33833,7 @@ package android.os { method public android.os.Bundle getUserRestrictions(); method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle); method public boolean hasUserRestriction(String); + method public boolean isAdminUser(); method public boolean isDemoUser(); method public static boolean isHeadlessSystemUserMode(); method public boolean isManagedProfile(); @@ -36889,6 +36889,7 @@ package android.provider { method public String[] getDocumentStreamTypes(String, String); method public String getDocumentType(String) throws java.io.FileNotFoundException; method public final String getType(android.net.Uri); + method @Nullable public final String getTypeAnonymous(@NonNull android.net.Uri); method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues); method public boolean isChildDocument(String, String); method public String moveDocument(String, String, String) throws java.io.FileNotFoundException; @@ -39765,6 +39766,7 @@ package android.service.autofill { method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender); method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull android.view.autofill.AutofillId, @Nullable android.service.autofill.Field); method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull String, @NonNull android.service.autofill.Field); + method @NonNull public android.service.autofill.Dataset.Builder setFieldForAllHints(@NonNull android.service.autofill.Field); method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String); method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation); method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation); @@ -39861,6 +39863,7 @@ package android.service.autofill { field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1 field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 + field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6 field public static final int UI_TYPE_DIALOG = 3; // 0x3 field public static final int UI_TYPE_INLINE = 2; // 0x2 field public static final int UI_TYPE_MENU = 1; // 0x1 @@ -40537,7 +40540,7 @@ package android.service.credentials { ctor public BeginCreateCredentialResponse(); method public int describeContents(); method @NonNull public java.util.List<android.service.credentials.CreateEntry> getCreateEntries(); - method @Nullable public android.service.credentials.CreateEntry getRemoteCreateEntry(); + method @Nullable public android.service.credentials.RemoteEntry getRemoteCreateEntry(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginCreateCredentialResponse> CREATOR; } @@ -40547,7 +40550,7 @@ package android.service.credentials { method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder addCreateEntry(@NonNull android.service.credentials.CreateEntry); method @NonNull public android.service.credentials.BeginCreateCredentialResponse build(); method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setCreateEntries(@NonNull java.util.List<android.service.credentials.CreateEntry>); - method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.CreateEntry); + method @NonNull @RequiresPermission("android.permission.PROVIDE_REMOTE_CREDENTIALS") public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.RemoteEntry); } public class BeginGetCredentialOption implements android.os.Parcelable { @@ -40582,7 +40585,7 @@ package android.service.credentials { method @NonNull public java.util.List<android.service.credentials.Action> getActions(); method @NonNull public java.util.List<android.service.credentials.Action> getAuthenticationActions(); method @NonNull public java.util.List<android.service.credentials.CredentialEntry> getCredentialEntries(); - method @Nullable public android.service.credentials.CredentialEntry getRemoteCredentialEntry(); + method @Nullable public android.service.credentials.RemoteEntry getRemoteCredentialEntry(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialResponse> CREATOR; } @@ -40596,7 +40599,7 @@ package android.service.credentials { method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setActions(@NonNull java.util.List<android.service.credentials.Action>); method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setAuthenticationActions(@NonNull java.util.List<android.service.credentials.Action>); method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setCredentialEntries(@NonNull java.util.List<android.service.credentials.CredentialEntry>); - method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.CredentialEntry); + method @NonNull @RequiresPermission("android.permission.PROVIDE_REMOTE_CREDENTIALS") public android.service.credentials.BeginGetCredentialResponse.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.RemoteEntry); } public final class CallingAppInfo implements android.os.Parcelable { @@ -40638,9 +40641,10 @@ package android.service.credentials { } public class CredentialEntry implements android.os.Parcelable { + ctor public CredentialEntry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice); ctor public CredentialEntry(@NonNull android.service.credentials.BeginGetCredentialOption, @NonNull android.app.slice.Slice); method public int describeContents(); - method @NonNull public android.service.credentials.BeginGetCredentialOption getBeginGetCredentialOption(); + method @NonNull public String getBeginGetCredentialOptionId(); method @NonNull public android.app.slice.Slice getSlice(); method @NonNull public String getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -40666,14 +40670,22 @@ package android.service.credentials { } public final class GetCredentialRequest implements android.os.Parcelable { - ctor public GetCredentialRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull android.credentials.CredentialOption); + ctor public GetCredentialRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull java.util.List<android.credentials.CredentialOption>); method public int describeContents(); method @NonNull public android.service.credentials.CallingAppInfo getCallingAppInfo(); - method @NonNull public android.credentials.CredentialOption getCredentialOption(); + method @NonNull public java.util.List<android.credentials.CredentialOption> getCredentialOptions(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialRequest> CREATOR; } + public class RemoteEntry implements android.os.Parcelable { + ctor public RemoteEntry(@NonNull android.app.slice.Slice); + method public int describeContents(); + method @NonNull public android.app.slice.Slice getSlice(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.RemoteEntry> CREATOR; + } + } package android.service.dreams { @@ -51433,7 +51445,7 @@ package android.view { public final class MotionPredictor { ctor public MotionPredictor(@NonNull android.content.Context); method public boolean isPredictionAvailable(int, int); - method @NonNull public java.util.List<android.view.MotionEvent> predict(long); + method @Nullable public android.view.MotionEvent predict(long); method public void record(@NonNull android.view.MotionEvent); } @@ -52022,8 +52034,8 @@ package android.view { method @Nullable public CharSequence getAccessibilityPaneTitle(); method @IdRes public int getAccessibilityTraversalAfter(); method @IdRes public int getAccessibilityTraversalBefore(); - method @NonNull public String getAllowedHandwritingDelegatePackageName(); - method @NonNull public String getAllowedHandwritingDelegatorPackageName(); + method @Nullable public String getAllowedHandwritingDelegatePackageName(); + method @Nullable public String getAllowedHandwritingDelegatorPackageName(); method public float getAlpha(); method public android.view.animation.Animation getAnimation(); method @Nullable public android.graphics.Matrix getAnimationMatrix(); @@ -52217,7 +52229,7 @@ package android.view { method public void invalidate(); method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable); method public void invalidateOutline(); - method public boolean isAccessibilityDataPrivate(); + method public boolean isAccessibilityDataSensitive(); method public boolean isAccessibilityFocused(); method public boolean isAccessibilityHeading(); method public boolean isActivated(); @@ -52397,7 +52409,7 @@ package android.view { method public void scrollTo(int, int); method public void sendAccessibilityEvent(int); method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent); - method public void setAccessibilityDataPrivate(int); + method public void setAccessibilityDataSensitive(int); method public void setAccessibilityDelegate(@Nullable android.view.View.AccessibilityDelegate); method public void setAccessibilityHeading(boolean); method public void setAccessibilityLiveRegion(int); @@ -52406,8 +52418,8 @@ package android.view { method public void setAccessibilityTraversalBefore(@IdRes int); method public void setActivated(boolean); method public void setAllowClickWhenDisabled(boolean); - method public void setAllowedHandwritingDelegatePackage(@NonNull String); - method public void setAllowedHandwritingDelegatorPackage(@NonNull String); + method public void setAllowedHandwritingDelegatePackage(@Nullable String); + method public void setAllowedHandwritingDelegatorPackage(@Nullable String); method public void setAlpha(@FloatRange(from=0.0, to=1.0) float); method public void setAnimation(android.view.animation.Animation); method public void setAnimationMatrix(@Nullable android.graphics.Matrix); @@ -52583,9 +52595,9 @@ package android.view { method @CallSuper protected boolean verifyDrawable(@NonNull android.graphics.drawable.Drawable); method @Deprecated public boolean willNotCacheDrawing(); method public boolean willNotDraw(); - field public static final int ACCESSIBILITY_DATA_PRIVATE_AUTO = 0; // 0x0 - field public static final int ACCESSIBILITY_DATA_PRIVATE_NO = 2; // 0x2 - field public static final int ACCESSIBILITY_DATA_PRIVATE_YES = 1; // 0x1 + field public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0; // 0x0 + field public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 2; // 0x2 + field public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 1; // 0x1 field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2 field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0 field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1 @@ -54055,11 +54067,11 @@ package android.view.accessibility { method public int getSpeechStateChangeTypes(); method public int getWindowChanges(); method public void initFromParcel(android.os.Parcel); - method public boolean isAccessibilityDataPrivate(); + method public boolean isAccessibilityDataSensitive(); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent); method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(); - method public void setAccessibilityDataPrivate(boolean); + method public void setAccessibilityDataSensitive(boolean); method public void setAction(int); method public void setContentChangeTypes(int); method public void setEventTime(long); @@ -54250,6 +54262,7 @@ package android.view.accessibility { method public int getWindowId(); method public boolean hasRequestInitialAccessibilityFocus(); method public boolean hasRequestTouchPassthrough(); + method public boolean isAccessibilityDataSensitive(); method public boolean isAccessibilityFocused(); method public boolean isCheckable(); method public boolean isChecked(); @@ -54286,6 +54299,7 @@ package android.view.accessibility { method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction); method public boolean removeChild(android.view.View); method public boolean removeChild(android.view.View, int); + method public void setAccessibilityDataSensitive(boolean); method public void setAccessibilityFocused(boolean); method public void setAvailableExtraData(java.util.List<java.lang.String>); method @Deprecated public void setBoundsInParent(android.graphics.Rect); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 9bab8cd8a94b..a8a48b75b155 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -254,7 +254,7 @@ package android { field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION"; field public static final String POWER_SAVER = "android.permission.POWER_SAVER"; field public static final String PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE = "android.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE"; - field public static final String PROVIDE_HYBRID_CREDENTIAL_SERVICE = "android.permission.PROVIDE_HYBRID_CREDENTIAL_SERVICE"; + field public static final String PROVIDE_REMOTE_CREDENTIALS = "android.permission.PROVIDE_REMOTE_CREDENTIALS"; field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE"; field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT"; field public static final String PROVISION_DEMO_DEVICE = "android.permission.PROVISION_DEMO_DEVICE"; @@ -3247,7 +3247,6 @@ package android.companion.virtual { method @NonNull public java.util.Set<android.content.ComponentName> getBlockedCrossTaskNavigations(); method public int getDefaultActivityPolicy(); method public int getDefaultNavigationPolicy(); - method public int getDefaultRecentsPolicy(); method public int getDevicePolicy(int); method public int getLockState(); method @Nullable public String getName(); @@ -3264,8 +3263,8 @@ package android.companion.virtual { field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0 field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1 field public static final int POLICY_TYPE_AUDIO = 1; // 0x1 + field public static final int POLICY_TYPE_RECENTS = 2; // 0x2 field public static final int POLICY_TYPE_SENSORS = 0; // 0x0 - field public static final int RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS = 1; // 0x1 } public static final class VirtualDeviceParams.Builder { @@ -3278,7 +3277,6 @@ package android.companion.virtual { method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAudioRecordingSessionId(int); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>); - method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDefaultRecentsPolicy(int); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int); method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String); @@ -3364,7 +3362,7 @@ package android.companion.virtual.sensor { } public static final class VirtualSensorConfig.Builder { - ctor public VirtualSensorConfig.Builder(int, @NonNull String); + ctor public VirtualSensorConfig.Builder(@IntRange(from=1) int, @NonNull String); method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build(); method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setDirectChannelTypesSupported(int); method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setHighestDirectReportRateLevel(int); @@ -9123,8 +9121,7 @@ package android.media.tv.tuner.frontend { method public int getProtocolCapability(); } - public class IptvFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { - method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettings.Builder builder(); + public final class IptvFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { method @IntRange(from=0) public long getBitrate(); method @NonNull public String getContentUrl(); method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress(); @@ -9145,6 +9142,7 @@ package android.media.tv.tuner.frontend { } public static final class IptvFrontendSettings.Builder { + ctor public IptvFrontendSettings.Builder(); method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings build(); method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setBitrate(@IntRange(from=0) long); method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setContentUrl(@NonNull String); @@ -9157,8 +9155,7 @@ package android.media.tv.tuner.frontend { method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setSrcPort(int); } - public class IptvFrontendSettingsFec { - method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder builder(); + public final class IptvFrontendSettingsFec { method @IntRange(from=0) public int getFecColNum(); method @IntRange(from=0) public int getFecRowNum(); method public int getFecType(); @@ -9169,6 +9166,7 @@ package android.media.tv.tuner.frontend { } public static final class IptvFrontendSettingsFec.Builder { + ctor public IptvFrontendSettingsFec.Builder(); method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec build(); method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecColNum(@IntRange(from=0) int); method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecRowNum(@IntRange(from=0) int); @@ -10001,34 +9999,65 @@ package android.net.wifi.nl80211 { package android.net.wifi.sharedconnectivity.app { - public final class DeviceInfo implements android.os.Parcelable { + public final class HotspotNetwork implements android.os.Parcelable { method public int describeContents(); - method @IntRange(from=0, to=100) public int getBatteryPercentage(); - method @IntRange(from=0, to=3) public int getConnectionStrength(); - method @NonNull public String getDeviceName(); - method public int getDeviceType(); - method @NonNull public String getModelName(); + method public long getDeviceId(); + method public int getHostNetworkType(); + method @Nullable public String getHotspotBssid(); + method @NonNull public java.util.Set<java.lang.Integer> getHotspotSecurityTypes(); + method @Nullable public String getHotspotSsid(); + method @NonNull public String getNetworkName(); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo getNetworkProviderInfo(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.DeviceInfo> CREATOR; - field public static final int DEVICE_TYPE_LAPTOP = 3; // 0x3 - field public static final int DEVICE_TYPE_PHONE = 1; // 0x1 - field public static final int DEVICE_TYPE_TABLET = 2; // 0x2 - field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0 + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.HotspotNetwork> CREATOR; + field public static final int NETWORK_TYPE_CELLULAR = 1; // 0x1 + field public static final int NETWORK_TYPE_ETHERNET = 3; // 0x3 + field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0 + field public static final int NETWORK_TYPE_WIFI = 2; // 0x2 } - public static final class DeviceInfo.Builder { - ctor public DeviceInfo.Builder(); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo build(); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setBatteryPercentage(@IntRange(from=0, to=100) int); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setDeviceName(@NonNull String); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setDeviceType(int); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setModelName(@NonNull String); + public static final class HotspotNetwork.Builder { + ctor public HotspotNetwork.Builder(); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder addHotspotSecurityType(int); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork build(); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setDeviceId(long); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHostNetworkType(int); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotBssid(@NonNull String); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotSsid(@NonNull String); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setNetworkName(@NonNull String); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setNetworkProviderInfo(@NonNull android.net.wifi.sharedconnectivity.app.NetworkProviderInfo); + } + + public final class HotspotNetworkConnectionStatus implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.os.Bundle getExtras(); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork getHotspotNetwork(); + method public int getStatus(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED = 9; // 0x9 + field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1; // 0x1 + field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED = 7; // 0x7 + field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT = 8; // 0x8 + field public static final int CONNECTION_STATUS_NO_CELL_DATA = 6; // 0x6 + field public static final int CONNECTION_STATUS_PROVISIONING_FAILED = 3; // 0x3 + field public static final int CONNECTION_STATUS_TETHERING_TIMEOUT = 4; // 0x4 + field public static final int CONNECTION_STATUS_TETHERING_UNSUPPORTED = 5; // 0x5 + field public static final int CONNECTION_STATUS_UNKNOWN = 0; // 0x0 + field public static final int CONNECTION_STATUS_UNKNOWN_ERROR = 2; // 0x2 + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus> CREATOR; + } + + public static final class HotspotNetworkConnectionStatus.Builder { + ctor public HotspotNetworkConnectionStatus.Builder(); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus build(); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.Builder setExtras(@NonNull android.os.Bundle); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.Builder setHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork); + method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.Builder setStatus(int); } public final class KnownNetwork implements android.os.Parcelable { method public int describeContents(); - method @Nullable public android.net.wifi.sharedconnectivity.app.DeviceInfo getDeviceInfo(); + method @Nullable public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo getNetworkProviderInfo(); method public int getNetworkSource(); method @NonNull public java.util.Set<java.lang.Integer> getSecurityTypes(); method @NonNull public String getSsid(); @@ -10043,7 +10072,7 @@ package android.net.wifi.sharedconnectivity.app { ctor public KnownNetwork.Builder(); method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder addSecurityType(int); method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork build(); - method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setDeviceInfo(@Nullable android.net.wifi.sharedconnectivity.app.DeviceInfo); + method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkProviderInfo(@Nullable android.net.wifi.sharedconnectivity.app.NetworkProviderInfo); method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkSource(int); method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setSsid(@NonNull String); } @@ -10068,27 +10097,54 @@ package android.net.wifi.sharedconnectivity.app { method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.Builder setStatus(int); } + public final class NetworkProviderInfo implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0, to=100) public int getBatteryPercentage(); + method @IntRange(from=0, to=3) public int getConnectionStrength(); + method @NonNull public String getDeviceName(); + method public int getDeviceType(); + method @NonNull public String getModelName(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.NetworkProviderInfo> CREATOR; + field public static final int DEVICE_TYPE_AUTO = 5; // 0x5 + field public static final int DEVICE_TYPE_LAPTOP = 3; // 0x3 + field public static final int DEVICE_TYPE_PHONE = 1; // 0x1 + field public static final int DEVICE_TYPE_TABLET = 2; // 0x2 + field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0 + field public static final int DEVICE_TYPE_WATCH = 4; // 0x4 + } + + public static final class NetworkProviderInfo.Builder { + ctor public NetworkProviderInfo.Builder(@NonNull String, @NonNull String); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo build(); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setBatteryPercentage(@IntRange(from=0, to=100) int); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceName(@NonNull String); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceType(int); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setModelName(@NonNull String); + } + public interface SharedConnectivityClientCallback { + method public void onHotspotNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus); + method public void onHotspotNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork>); method public void onKnownNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus); method public void onKnownNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>); method public void onRegisterCallbackFailed(@NonNull Exception); method public void onServiceConnected(); method public void onServiceDisconnected(); method public void onSharedConnectivitySettingsChanged(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState); - method public void onTetherNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus); - method public void onTetherNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork>); } public class SharedConnectivityManager { + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean connectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean connectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean connectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean disconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean disconnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork); + method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus(); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork> getHotspotNetworks(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus getKnownNetworkConnectionStatus(); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork> getKnownNetworks(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState getSettingsState(); - method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus getTetherNetworkConnectionStatus(); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork> getTetherNetworks(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback); } @@ -10108,62 +10164,6 @@ package android.net.wifi.sharedconnectivity.app { method @NonNull public android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState.Builder setInstantTetherEnabled(boolean); } - public final class TetherNetwork implements android.os.Parcelable { - method public int describeContents(); - method public long getDeviceId(); - method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo getDeviceInfo(); - method @Nullable public String getHotspotBssid(); - method @NonNull public java.util.Set<java.lang.Integer> getHotspotSecurityTypes(); - method @Nullable public String getHotspotSsid(); - method @NonNull public String getNetworkName(); - method public int getNetworkType(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.TetherNetwork> CREATOR; - field public static final int NETWORK_TYPE_CELLULAR = 1; // 0x1 - field public static final int NETWORK_TYPE_ETHERNET = 3; // 0x3 - field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0 - field public static final int NETWORK_TYPE_WIFI = 2; // 0x2 - } - - public static final class TetherNetwork.Builder { - ctor public TetherNetwork.Builder(); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder addHotspotSecurityType(int); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork build(); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setDeviceId(long); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setDeviceInfo(@NonNull android.net.wifi.sharedconnectivity.app.DeviceInfo); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setHotspotBssid(@NonNull String); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setHotspotSsid(@NonNull String); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setNetworkName(@NonNull String); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setNetworkType(int); - } - - public final class TetherNetworkConnectionStatus implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.os.Bundle getExtras(); - method public int getStatus(); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork getTetherNetwork(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED = 9; // 0x9 - field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1; // 0x1 - field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED = 7; // 0x7 - field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT = 8; // 0x8 - field public static final int CONNECTION_STATUS_NO_CELL_DATA = 6; // 0x6 - field public static final int CONNECTION_STATUS_PROVISIONING_FAILED = 3; // 0x3 - field public static final int CONNECTION_STATUS_TETHERING_TIMEOUT = 4; // 0x4 - field public static final int CONNECTION_STATUS_TETHERING_UNSUPPORTED = 5; // 0x5 - field public static final int CONNECTION_STATUS_UNKNOWN = 0; // 0x0 - field public static final int CONNECTION_STATUS_UNKNOWN_ERROR = 2; // 0x2 - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus> CREATOR; - } - - public static final class TetherNetworkConnectionStatus.Builder { - ctor public TetherNetworkConnectionStatus.Builder(); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus build(); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.Builder setExtras(@NonNull android.os.Bundle); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.Builder setStatus(int); - method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.Builder setTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork); - } - } package android.net.wifi.sharedconnectivity.service { @@ -10171,15 +10171,15 @@ package android.net.wifi.sharedconnectivity.service { public abstract class SharedConnectivityService extends android.app.Service { ctor public SharedConnectivityService(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public abstract void onConnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork); method public abstract void onConnectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork); - method public abstract void onConnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork); - method public abstract void onDisconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork); + method public abstract void onDisconnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork); method public abstract void onForgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork); + method public final void setHotspotNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork>); method public final void setKnownNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>); method public final void setSettingsState(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState); - method public final void setTetherNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork>); + method public final void updateHotspotNetworkConnectionStatus(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus); method public final void updateKnownNetworkConnectionStatus(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus); - method public final void updateTetherNetworkConnectionStatus(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus); } } @@ -10960,7 +10960,6 @@ package android.os { method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public java.util.Set<android.os.UserHandle> getVisibleUsers(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle); - method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser(); method public boolean isCloneProfile(); method @Deprecated public boolean isCredentialSharableWithParent(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser(); @@ -13167,7 +13166,7 @@ package android.service.voice { method @NonNull public android.service.voice.HotwordDetectedResult.Builder setScore(int); } - public abstract class HotwordDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionServiceBase { + public abstract class HotwordDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionInitializer { ctor public HotwordDetectionService(); method @Deprecated public static int getMaxCustomInitializationStatus(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); @@ -13239,7 +13238,7 @@ package android.service.voice { method @NonNull public android.service.voice.HotwordRejectedResult.Builder setConfidenceLevel(int); } - public interface SandboxedDetectionServiceBase { + public interface SandboxedDetectionInitializer { method public static int getMaxCustomInitializationStatus(); method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer); field public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0 @@ -13261,7 +13260,7 @@ package android.service.voice { field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.UnknownFailure> CREATOR; } - public abstract class VisualQueryDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionServiceBase { + public abstract class VisualQueryDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionInitializer { ctor public VisualQueryDetectionService(); method public final void finishQuery() throws java.lang.IllegalStateException; method public final void gainedAttention(); @@ -13789,7 +13788,7 @@ package android.telecom { field public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE = "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE"; field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE"; field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE"; - field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT"; + field @Deprecated public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT"; field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE"; field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE"; field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL"; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 43fa6e262a14..85163eda04b0 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -899,6 +899,7 @@ package android.content.pm { field public static final float OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE = 1.5f; field public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // 0xc2368d6L field public static final long OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN = 208648326L; // 0xc6fb886L + field public static final long OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS = 237531167L; // 0xe28701fL field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2 } @@ -2629,8 +2630,13 @@ package android.service.autofill { method @Nullable public android.content.IntentSender getAuthentication(); method @Nullable public java.util.ArrayList<java.lang.String> getAutofillDatatypes(); method @Nullable public android.content.ClipData getFieldContent(); + method @Nullable public android.widget.RemoteViews getFieldDialogPresentation(int); method @Nullable public java.util.ArrayList<android.view.autofill.AutofillId> getFieldIds(); + method @Nullable public android.service.autofill.InlinePresentation getFieldInlinePresentation(int); + method @Nullable public android.service.autofill.InlinePresentation getFieldInlineTooltipPresentation(int); + method @Nullable public android.widget.RemoteViews getFieldPresentation(int); method @Nullable public java.util.ArrayList<android.view.autofill.AutofillValue> getFieldValues(); + method @Nullable public android.service.autofill.Dataset.DatasetFieldFilter getFilter(int); method @Nullable public String getId(); method public boolean isEmpty(); } @@ -2639,6 +2645,13 @@ package android.service.autofill { method @NonNull public android.service.autofill.Dataset.Builder setContent(@NonNull android.view.autofill.AutofillId, @Nullable android.content.ClipData); } + public static final class Dataset.DatasetFieldFilter implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public java.util.regex.Pattern getPattern(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.Dataset.DatasetFieldFilter> CREATOR; + } + public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation { method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception; } @@ -2812,7 +2825,7 @@ package android.service.voice { method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>); } - public abstract class HotwordDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionServiceBase { + public abstract class HotwordDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionInitializer { field public static final boolean ENABLE_PROXIMITY_RESULT = true; } @@ -3291,7 +3304,9 @@ package android.view { } @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { + method public void getBoundsOnScreen(@NonNull android.graphics.Rect, boolean); method public android.view.View getTooltipView(); + method public void getWindowDisplayFrame(@NonNull android.graphics.Rect); method public boolean isAutofilled(); method public static boolean isDefaultFocusHighlightEnabled(); method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable); @@ -3342,6 +3357,7 @@ package android.view { field public static final int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1; // 0x1 field public static final int DISPLAY_IME_POLICY_HIDE = 2; // 0x2 field public static final int DISPLAY_IME_POLICY_LOCAL = 0; // 0x0 + field public static final int LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP = 600; // 0x258 } public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable { @@ -3418,6 +3434,7 @@ package android.view.autofill { } public final class AutofillManager { + field public static final String ANY_HINT = "any"; field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0 field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1 field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0 @@ -3772,6 +3789,7 @@ package android.window { public final class TaskFragmentInfo implements android.os.Parcelable { method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo); method @NonNull public java.util.List<android.os.IBinder> getActivities(); + method @NonNull public java.util.List<android.os.IBinder> getActivitiesRequestedInTaskFragment(); method @NonNull public android.content.res.Configuration getConfiguration(); method @NonNull public android.os.IBinder getFragmentToken(); method @NonNull public android.graphics.Point getPositionInParent(); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d9c7a27cb95e..125e7270b0e2 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6621,7 +6621,9 @@ public class Activity extends ContextThemeWrapper * the incoming activity. Use 0 for no animation. * @param exitAnim A resource ID of the animation resource to use for * the outgoing activity. Use 0 for no animation. + * @deprecated Use {@link #overrideActivityTransition(int, int, int)}} instead. */ + @Deprecated public void overridePendingTransition(int enterAnim, int exitAnim) { overridePendingTransition(enterAnim, exitAnim, 0); } @@ -6644,7 +6646,9 @@ public class Activity extends ContextThemeWrapper * the outgoing activity. Use 0 for no animation. * @param backgroundColor The background color to use for the background during the animation if * the animation requires a background. Set to 0 to not override the default color. + * @deprecated Use {@link #overrideActivityTransition(int, int, int, int)}} instead. */ + @Deprecated public void overridePendingTransition(int enterAnim, int exitAnim, int backgroundColor) { ActivityClient.getInstance().overridePendingTransition(mToken, getPackageName(), enterAnim, exitAnim, backgroundColor); diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java index 44327af928cb..b35e87b541d3 100644 --- a/core/java/android/app/ActivityClient.java +++ b/core/java/android/app/ActivityClient.java @@ -598,6 +598,23 @@ public class ActivityClient { } /** + * Returns {@code true} if the activity was explicitly requested to be launched in the + * TaskFragment. + * + * @param activityToken The token of the Activity. + * @param taskFragmentToken The token of the TaskFragment. + */ + public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken, + IBinder taskFragmentToken) { + try { + return getActivityClientController().isRequestedToLaunchInTaskFragment(activityToken, + taskFragmentToken); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Shows or hides a Camera app compat toggle for stretched issues with the requested state. * * @param token The token for the window that needs a control. diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index ba36d937edc3..3c792a3ef5f9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -630,7 +630,7 @@ public class ActivityManager { PROCESS_CAPABILITY_FOREGROUND_LOCATION, PROCESS_CAPABILITY_FOREGROUND_CAMERA, PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, - PROCESS_CAPABILITY_NETWORK, + PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK, PROCESS_CAPABILITY_BFSL, }) @Retention(RetentionPolicy.SOURCE) @@ -791,7 +791,7 @@ public class ActivityManager { public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION | PROCESS_CAPABILITY_FOREGROUND_CAMERA | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE - | PROCESS_CAPABILITY_NETWORK + | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK | PROCESS_CAPABILITY_BFSL; /** @@ -810,7 +810,7 @@ public class ActivityManager { pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-'); pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-'); pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-'); - pw.print((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-'); + pw.print((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-'); pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-'); } @@ -819,7 +819,7 @@ public class ActivityManager { sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-'); sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-'); sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-'); - sb.append((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-'); + sb.append((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-'); sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-'); } @@ -4208,7 +4208,7 @@ public class ActivityManager { * processes to reclaim memory; the system will take care of restarting * these processes in the future as needed. * - * <p class="note">On devices with a {@link Build.VERSION#SECURITY_PATCH} of 2022-12-01 or + * <p class="note">On devices with a {@link Build.VERSION#SECURITY_PATCH} of 2023-08-01 or * greater, third party applications can only use this API to kill their own processes. * </p> * diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index dfdfd0e2054e..a3ada763265a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1154,6 +1154,11 @@ public final class ActivityThread extends ClientTransactionHandler } @Override + public final void schedulePing(RemoteCallback pong) { + sendMessage(H.PING, pong); + } + + @Override public final void bindApplication(String processName, ApplicationInfo appInfo, String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage, ProviderInfoList providerList, ComponentName instrumentationName, @@ -2154,6 +2159,7 @@ public final class ActivityThread extends ClientTransactionHandler public static final int DUMP_GFXINFO = 165; public static final int DUMP_RESOURCES = 166; public static final int TIMEOUT_SERVICE = 167; + public static final int PING = 168; public static final int INSTRUMENT_WITHOUT_RESTART = 170; public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171; @@ -2209,6 +2215,7 @@ public final class ActivityThread extends ClientTransactionHandler return "FINISH_INSTRUMENTATION_WITHOUT_RESTART"; case DUMP_RESOURCES: return "DUMP_RESOURCES"; case TIMEOUT_SERVICE: return "TIMEOUT_SERVICE"; + case PING: return "PING"; } } return Integer.toString(code); @@ -2292,6 +2299,9 @@ public final class ActivityThread extends ClientTransactionHandler handleTimeoutService((IBinder) msg.obj, msg.arg1); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; + case PING: + ((RemoteCallback) msg.obj).sendResult(null); + break; case CONFIGURATION_CHANGED: mConfigurationController.handleConfigurationChanged((Configuration) msg.obj); break; diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index 5136b2033d1c..a3c5e1c67e1b 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -181,4 +181,14 @@ interface IActivityClientController { * that started the task. */ void enableTaskLocaleOverride(in IBinder token); + + /** + * Return {@code true} if the activity was explicitly requested to be launched in the + * TaskFragment. + * + * @param activityToken The token of the Activity. + * @param taskFragmentToken The token of the TaskFragment. + */ + boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken, + in IBinder taskFragmentToken); } diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index dad9b435e9e7..4f77203c8c6f 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -172,4 +172,5 @@ oneway interface IApplicationThread { in TranslationSpec targetSpec, in List<AutofillId> viewIds, in UiTranslationSpec uiTranslationSpec); void scheduleTimeoutService(IBinder token, int startId); + void schedulePing(in RemoteCallback pong); } diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java index f4cd60d08804..97cc706fbab6 100644 --- a/core/java/android/app/LocaleConfig.java +++ b/core/java/android/app/LocaleConfig.java @@ -58,10 +58,10 @@ import java.util.Set; * * @attr ref android.R.styleable#LocaleConfig_Locale_name * @attr ref android.R.styleable#AndroidManifestApplication_localeConfig - * - * <p>For more information about the LocaleConfig overridden by the application, see - * TODO(b/261528306): add link to guide */ +// Add following to last Note: when guide is written: +// For more information about the LocaleConfig overridden by the application, see TODO(b/261528306): +// add link to guide public class LocaleConfig implements Parcelable { private static final String TAG = "LocaleConfig"; public static final String TAG_LOCALE_CONFIG = "locale-config"; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 83e015357589..dbba0c6f5e50 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -509,7 +509,7 @@ public final class SystemServiceRegistry { new ServiceFetcher<InputManager>() { @Override public InputManager getService(ContextImpl ctx) { - return InputManager.getInstance(ctx); + return InputManager.getInstance(ctx.getOuterContext()); }}); registerService(Context.DISPLAY_SERVICE, DisplayManager.class, diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index de4f619392c1..a522cc04eff1 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -801,6 +801,119 @@ public final class CompanionDeviceManager { } /** + * Listener for any changes to {@link com.android.server.companion.transport.Transport}. + * + * @hide + */ + public interface OnTransportsChangedListener { + /** + * Invoked when a change occurs to any of the transports + * + * @param associations all the associations which have connected transports + */ + void onTransportsChanged(@NonNull List<AssociationInfo> associations); + } + + /** + * Register a listener for any changes to + * {@link com.android.server.companion.transport.Transport}. Your app will receive a callback to + * {@link OnTransportsChangedListener} immediately with all the existing transports. + * + * @hide + */ + public void addOnTransportsChangedListener( + @NonNull Executor executor, @NonNull OnTransportsChangedListener listener) { + final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy( + executor, listener); + try { + mService.addOnTransportsChangedListener(proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregister a listener to stop receiving any changes to + * {@link com.android.server.companion.transport.Transport}. + * + * @hide + */ + public void removeOnTransportsChangedListener( + @NonNull OnTransportsChangedListener listener) { + final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy( + null, listener); + try { + mService.removeOnTransportsChangedListener(proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Send a message to remote devices + * + * @hide + */ + public void sendMessage(int messageType, byte[] data, int[] associationIds) { + try { + mService.sendMessage(messageType, data, associationIds); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Listener when a message is received for the registered message type + * + * @see #addOnMessageReceivedListener(Executor, int, OnMessageReceivedListener) + * + * @hide + */ + public interface OnMessageReceivedListener { + /** + * Called when a message is received + */ + void onMessageReceived(int associationId, byte[] data); + } + + /** + * Register a listener to receive callbacks when a message is received by the given type + * + * @see com.android.server.companion.transport.Transport for supported message types + * + * @hide + */ + public void addOnMessageReceivedListener(@NonNull Executor executor, int messageType, + OnMessageReceivedListener listener) { + final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy( + executor, listener); + try { + mService.addOnMessageReceivedListener(messageType, proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregister a listener to stop receiving callbacks when a message is received by the given + * type + * + * @see com.android.server.companion.transport.Transport for supported message types + * + * @hide + */ + public void removeOnMessageReceivedListener(int messageType, + OnMessageReceivedListener listener) { + final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy( + null, listener); + try { + mService.removeOnMessageReceivedListener(messageType, proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Checks whether the bluetooth device represented by the mac address was recently associated * with the companion app. This allows these devices to skip the Bluetooth pairing dialog if * their pairing variant is {@link BluetoothDevice#PAIRING_VARIANT_CONSENT}. @@ -1277,6 +1390,40 @@ public final class CompanionDeviceManager { } } + private static class OnTransportsChangedListenerProxy + extends IOnTransportsChangedListener.Stub { + private final Executor mExecutor; + private final OnTransportsChangedListener mListener; + + private OnTransportsChangedListenerProxy(Executor executor, + OnTransportsChangedListener listener) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onTransportsChanged(@NonNull List<AssociationInfo> associations) { + mExecutor.execute(() -> mListener.onTransportsChanged(associations)); + } + } + + private static class OnMessageReceivedListenerProxy + extends IOnMessageReceivedListener.Stub { + private final Executor mExecutor; + private final OnMessageReceivedListener mListener; + + private OnMessageReceivedListenerProxy(Executor executor, + OnMessageReceivedListener listener) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onMessageReceived(int associationId, byte[] data) { + mExecutor.execute(() -> mListener.onMessageReceived(associationId, data)); + } + } + private static class SystemDataTransferCallbackProxy extends ISystemDataTransferCallback.Stub { private final Executor mExecutor; private final OutcomeReceiver<Void, CompanionException> mCallback; diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index cb4baca73ba0..b5e2670e5299 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -19,6 +19,8 @@ package android.companion; import android.app.PendingIntent; import android.companion.IAssociationRequestCallback; import android.companion.IOnAssociationsChangedListener; +import android.companion.IOnMessageReceivedListener; +import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.companion.AssociationInfo; import android.companion.AssociationRequest; @@ -67,6 +69,16 @@ interface ICompanionDeviceManager { void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId); + void addOnTransportsChangedListener(IOnTransportsChangedListener listener); + + void removeOnTransportsChangedListener(IOnTransportsChangedListener listener); + + void sendMessage(int messageType, in byte[] data, in int[] associationIds); + + void addOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener); + + void removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener); + void notifyDeviceAppeared(int associationId); void notifyDeviceDisappeared(int associationId); diff --git a/core/java/android/companion/IOnMessageReceivedListener.aidl b/core/java/android/companion/IOnMessageReceivedListener.aidl new file mode 100644 index 000000000000..17f03f80996e --- /dev/null +++ b/core/java/android/companion/IOnMessageReceivedListener.aidl @@ -0,0 +1,23 @@ +/* + * 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 per missions and + * limitations under the License. + */ + +package android.companion; + +/** @hide */ +interface IOnMessageReceivedListener { + + oneway void onMessageReceived(int associationId, in byte[] data); +}
\ No newline at end of file diff --git a/core/java/android/companion/IOnTransportsChangedListener.aidl b/core/java/android/companion/IOnTransportsChangedListener.aidl new file mode 100644 index 000000000000..a10147627a9d --- /dev/null +++ b/core/java/android/companion/IOnTransportsChangedListener.aidl @@ -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 per missions and + * limitations under the License. + */ + +package android.companion; + +import android.companion.AssociationInfo; + +/** @hide */ +interface IOnTransportsChangedListener { + + oneway void onTransportsChanged(in List<AssociationInfo> associations); +}
\ No newline at end of file diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index 6cc4c8a24c48..90681cba7d83 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -545,12 +545,13 @@ public final class VirtualDeviceManager { @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { - VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( + VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( getVirtualDisplayName(), width, height, densityDpi) - .setSurface(surface) - .setFlags(flags) - .build(); - return createVirtualDisplay(config, executor, callback); + .setFlags(flags); + if (surface != null) { + builder.setSurface(surface); + } + return createVirtualDisplay(builder.build(), executor, callback); } /** diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index 9f3b60148004..3a60a695a294 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -140,7 +140,8 @@ public final class VirtualDeviceParams implements Parcelable { * a given policy type. * @hide */ - @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO}) + @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO, + POLICY_TYPE_RECENTS}) @Retention(RetentionPolicy.SOURCE) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) public @interface PolicyType {} @@ -169,22 +170,21 @@ public final class VirtualDeviceParams implements Parcelable { * <li>{@link #DEVICE_POLICY_CUSTOM}: audio framework will assign device specific session * ids to players and recorders constructed within device context. The session ids are * used to re-route corresponding audio streams to VirtualAudioDevice. - * <ul/> + * </ul> */ public static final int POLICY_TYPE_AUDIO = 1; - /** @hide */ - @IntDef(flag = true, prefix = "RECENTS_POLICY_", - value = {RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS}) - @Retention(RetentionPolicy.SOURCE) - @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) - public @interface RecentsPolicy {} - /** - * If set, activities launched on this virtual device are allowed to appear in the host device - * of the recently launched activities list. + * Tells the activity manager how to handle recents entries for activities run on this device. + * + * <ul> + * <li>{@link #DEVICE_POLICY_DEFAULT}: Activities launched on VirtualDisplays owned by this + * device will appear in the host device recents. + * <li>{@link #DEVICE_POLICY_CUSTOM}: Activities launched on VirtualDisplays owned by this + * * device will not appear in recents. + * </ul> */ - public static final int RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS = 1 << 0; + public static final int POLICY_TYPE_RECENTS = 2; private final int mLockState; @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts; @@ -201,8 +201,6 @@ public final class VirtualDeviceParams implements Parcelable { @NonNull private final SparseIntArray mDevicePolicies; @NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs; @Nullable private final IVirtualSensorCallback mVirtualSensorCallback; - @RecentsPolicy - private final int mDefaultRecentsPolicy; private final int mAudioPlaybackSessionId; private final int mAudioRecordingSessionId; @@ -219,7 +217,6 @@ public final class VirtualDeviceParams implements Parcelable { @NonNull SparseIntArray devicePolicies, @NonNull List<VirtualSensorConfig> virtualSensorConfigs, @Nullable IVirtualSensorCallback virtualSensorCallback, - @RecentsPolicy int defaultRecentsPolicy, int audioPlaybackSessionId, int audioRecordingSessionId) { mLockState = lockState; @@ -237,10 +234,8 @@ public final class VirtualDeviceParams implements Parcelable { mDevicePolicies = Objects.requireNonNull(devicePolicies); mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs); mVirtualSensorCallback = virtualSensorCallback; - mDefaultRecentsPolicy = defaultRecentsPolicy; mAudioPlaybackSessionId = audioPlaybackSessionId; mAudioRecordingSessionId = audioRecordingSessionId; - } @SuppressWarnings("unchecked") @@ -259,7 +254,6 @@ public final class VirtualDeviceParams implements Parcelable { parcel.readTypedList(mVirtualSensorConfigs, VirtualSensorConfig.CREATOR); mVirtualSensorCallback = IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder()); - mDefaultRecentsPolicy = parcel.readInt(); mAudioPlaybackSessionId = parcel.readInt(); mAudioRecordingSessionId = parcel.readInt(); } @@ -396,16 +390,6 @@ public final class VirtualDeviceParams implements Parcelable { } /** - * Returns the policy of how to handle activities in recents. - * - * @see RecentsPolicy - */ - @RecentsPolicy - public int getDefaultRecentsPolicy() { - return mDefaultRecentsPolicy; - } - - /** * Returns device-specific audio session id for playback. * * @see Builder#setAudioPlaybackSessionId(int) @@ -443,7 +427,6 @@ public final class VirtualDeviceParams implements Parcelable { dest.writeTypedList(mVirtualSensorConfigs); dest.writeStrongBinder( mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null); - dest.writeInt(mDefaultRecentsPolicy); dest.writeInt(mAudioPlaybackSessionId); dest.writeInt(mAudioRecordingSessionId); } @@ -478,7 +461,6 @@ public final class VirtualDeviceParams implements Parcelable { && Objects.equals(mBlockedActivities, that.mBlockedActivities) && mDefaultActivityPolicy == that.mDefaultActivityPolicy && Objects.equals(mName, that.mName) - && mDefaultRecentsPolicy == that.mDefaultRecentsPolicy && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId && mAudioRecordingSessionId == that.mAudioRecordingSessionId; } @@ -489,7 +471,7 @@ public final class VirtualDeviceParams implements Parcelable { mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations, mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities, mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies, - mDefaultRecentsPolicy, mAudioPlaybackSessionId, mAudioRecordingSessionId); + mAudioPlaybackSessionId, mAudioRecordingSessionId); for (int i = 0; i < mDevicePolicies.size(); i++) { hashCode = 31 * hashCode + mDevicePolicies.keyAt(i); hashCode = 31 * hashCode + mDevicePolicies.valueAt(i); @@ -511,7 +493,6 @@ public final class VirtualDeviceParams implements Parcelable { + " mDefaultActivityPolicy=" + mDefaultActivityPolicy + " mName=" + mName + " mDevicePolicies=" + mDevicePolicies - + " mDefaultRecentsPolicy=" + mDefaultRecentsPolicy + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId + " mAudioRecordingSessionId=" + mAudioRecordingSessionId + ")"; @@ -548,7 +529,6 @@ public final class VirtualDeviceParams implements Parcelable { private boolean mDefaultActivityPolicyConfigured = false; @Nullable private String mName; @NonNull private SparseIntArray mDevicePolicies = new SparseIntArray(); - private int mDefaultRecentsPolicy; private int mAudioPlaybackSessionId = AUDIO_SESSION_ID_GENERATE; private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE; @@ -821,17 +801,6 @@ public final class VirtualDeviceParams implements Parcelable { } /** - * Sets the policy to indicate how activities are handled in recents. - * - * @param defaultRecentsPolicy A policy specifying how to handle activities in recents. - */ - @NonNull - public Builder setDefaultRecentsPolicy(@RecentsPolicy int defaultRecentsPolicy) { - mDefaultRecentsPolicy = defaultRecentsPolicy; - return this; - } - - /** * Sets audio playback session id specific for this virtual device. * * <p>Audio players constructed within context associated with this virtual device @@ -933,7 +902,6 @@ public final class VirtualDeviceParams implements Parcelable { mDevicePolicies, mVirtualSensorConfigs, mVirtualSensorCallback, - mDefaultRecentsPolicy, mAudioPlaybackSessionId, mAudioRecordingSessionId); } diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java index ffbdff8c2e3b..401e754abca6 100644 --- a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java +++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java @@ -17,6 +17,7 @@ package android.companion.virtual.sensor; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -167,7 +168,10 @@ public final class VirtualSensorConfig implements Parcelable { * @param name The name of the sensor. Must be unique among all sensors with the same type * that belong to the same virtual device. */ - public Builder(int type, @NonNull String name) { + public Builder(@IntRange(from = 1) int type, @NonNull String name) { + if (type <= 0) { + throw new IllegalArgumentException("Virtual sensor type must be positive"); + } mType = type; mName = Objects.requireNonNull(name); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d0accb72a0e1..36f7ff53eb76 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -316,10 +316,12 @@ public abstract class Context { BIND_ALLOW_ACTIVITY_STARTS, BIND_INCLUDE_CAPABILITIES, BIND_SHARED_ISOLATED_PROCESS, - // Intentionally not included, because it'd cause sign-extension. + // Intentionally not include BIND_EXTERNAL_SERVICE, because it'd cause sign-extension. // This would allow Android Studio to show a warning, if someone tries to use // BIND_EXTERNAL_SERVICE BindServiceFlags. - BIND_EXTERNAL_SERVICE_LONG + BIND_EXTERNAL_SERVICE_LONG, + // Make sure no flag uses the sign bit (most significant bit) of the long integer, + // to avoid future confusion. }) @Retention(RetentionPolicy.SOURCE) public @interface BindServiceFlagsLongBits {} @@ -338,6 +340,7 @@ public abstract class Context { /** * @return Return flags in 64 bits long integer. + * @hide */ public long getValue() { return mValue; @@ -528,7 +531,7 @@ public abstract class Context { /** * Flag for {@link #bindService}: allow the process hosting the target service to gain - * {@link ActivityManager#PROCESS_CAPABILITY_NETWORK}, which allows it be able + * {@link ActivityManager#PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK}, which allows it be able * to access network regardless of any power saving restrictions. * * @hide @@ -678,13 +681,11 @@ public abstract class Context { */ public static final int BIND_EXTERNAL_SERVICE = 0x80000000; - /** * Works in the same way as {@link #BIND_EXTERNAL_SERVICE}, but it's defined as a (@code long) * value that is compatible to {@link BindServiceFlags}. */ - public static final long BIND_EXTERNAL_SERVICE_LONG = 0x8000_0000_0000_0000L; - + public static final long BIND_EXTERNAL_SERVICE_LONG = 1L << 62; /** * These bind flags reduce the strength of the binding such that we shouldn't diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index f8f2663063a6..eb14cc4802ad 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1156,6 +1156,34 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { 264301586L; // buganizer id /** + * This change id forces the packages it is applied to sandbox {@link android.view.View} API to + * an activity bounds for: + * + * <p>{@link android.view.View#getLocationOnScreen}, + * {@link android.view.View#getWindowVisibleDisplayFrame}, + * {@link android.view.View}#getWindowDisplayFrame, + * {@link android.view.View}#getBoundsOnScreen. + * + * <p>For {@link android.view.View#getWindowVisibleDisplayFrame} and + * {@link android.view.View}#getWindowDisplayFrame this sandboxing is happening indirectly + * through + * {@link android.view.ViewRootImpl}#getWindowVisibleDisplayFrame, + * {@link android.view.ViewRootImpl}#getDisplayFrame respectively. + * + * <p>Some applications assume that they occupy the whole screen and therefore use the display + * coordinates in their calculations as if an activity is positioned in the top-left corner of + * the screen, with left coordinate equal to 0. This may not be the case of applications in + * multi-window and in letterbox modes. This can lead to shifted or out of bounds UI elements in + * case the activity is Letterboxed or is in multi-window mode. + * @hide + */ + @ChangeId + @Overridable + @Disabled + @TestApi + public static final long OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS = 237531167L; // buganizer id + + /** * This change id is the gatekeeper for all treatments that force a given min aspect ratio. * Enabling this change will allow the following min aspect ratio treatments to be applied: * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index a6a62150d0da..cb988dfdb203 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -2935,13 +2935,14 @@ public class PackageInstaller { * <li>The {@link InstallSourceInfo#getUpdateOwnerPackageName() update owner} * of an existing version of the app (in other words, this install session is * an app update) if the update ownership enforcement is enabled.</li> - * <li>The {@link InstallSourceInfo#getInstallingPackageName() installer of - * record} of an existing version of the app (in other words, this install + * <li>The + * {@link InstallSourceInfo#getInstallingPackageName() installer of record} + * of an existing version of the app (in other words, this install * session is an app update) if the update ownership enforcement isn't * enabled.</li> * <li>Updating itself.</li> * </ul> - * </li>> + * </li> * <li>The installer declares the * {@link android.Manifest.permission#UPDATE_PACKAGES_WITHOUT_USER_ACTION * UPDATE_PACKAGES_WITHOUT_USER_ACTION} permission.</li> diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING index f440ac7ecbb2..b6012757c35d 100644 --- a/core/java/android/content/pm/TEST_MAPPING +++ b/core/java/android/content/pm/TEST_MAPPING @@ -28,6 +28,9 @@ "path": "cts/hostsidetests/os/test_mappings/packagemanager" }, { + "path": "cts/hostsidetests/appsearch" + }, + { "path": "system/apex/tests" }, { @@ -46,6 +49,12 @@ "name": "ApkVerityTest" }, { + "name": "CtsSilentUpdateHostTestCases" + }, + { + "name": "CtsSuspendAppsTestCases" + }, + { "name": "CtsAppFgsTestCases", "file_patterns": ["(/|^)ServiceInfo[^/]*"], "options": [ @@ -111,39 +120,6 @@ ] }, { - "name": "CtsAppSearchHostTestCases", - "options": [ - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-annotation": "org.junit.Ignore" - } - ] - }, - { - "name": "CtsSilentUpdateHostTestCases", - "options": [ - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-annotation": "org.junit.Ignore" - } - ] - }, - { - "name": "CtsSuspendAppsTestCases", - "options": [ - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-annotation": "org.junit.Ignore" - } - ] - }, - { "name": "CtsSuspendAppsPermissionTestCases", "options": [ { diff --git a/core/java/android/credentials/CreateCredentialRequest.java b/core/java/android/credentials/CreateCredentialRequest.java index c89a5c62cd58..fc3dc796d3ed 100644 --- a/core/java/android/credentials/CreateCredentialRequest.java +++ b/core/java/android/credentials/CreateCredentialRequest.java @@ -260,11 +260,17 @@ public final class CreateCredentialRequest implements Parcelable { private String mOrigin; /** + * @param type the type of the credential to be stored * @param credentialData the full credential creation request data * @param candidateQueryData the partial request data that will be sent to the provider * during the initial creation candidate query stage */ - public Builder(@NonNull Bundle credentialData, @NonNull Bundle candidateQueryData) { + public Builder( + @NonNull String type, + @NonNull Bundle credentialData, + @NonNull Bundle candidateQueryData) { + mType = Preconditions.checkStringNotEmpty(type, + "type must not be null or empty"); mCredentialData = requireNonNull(credentialData, "credentialData must not be null"); mCandidateQueryData = requireNonNull(candidateQueryData, @@ -291,16 +297,6 @@ public final class CreateCredentialRequest implements Parcelable { } /** - * Sets the requested credential type. - */ - @SuppressLint("MissingGetterMatchingBuilder") - @NonNull - public CreateCredentialRequest.Builder setType(@NonNull String type) { - mType = type; - return this; - } - - /** * Sets whether the request must only be fulfilled by a system provider. * This defaults to false */ diff --git a/core/java/android/credentials/GetCredentialRequest.java b/core/java/android/credentials/GetCredentialRequest.java index 951cbe4e58c0..c58d2dcd2dbf 100644 --- a/core/java/android/credentials/GetCredentialRequest.java +++ b/core/java/android/credentials/GetCredentialRequest.java @@ -149,7 +149,6 @@ public final class GetCredentialRequest implements Parcelable { mCredentialOptions = credentialOptions; AnnotationValidations.validate(NonNull.class, null, mCredentialOptions); - Bundle data = in.readBundle(); mData = data; AnnotationValidations.validate(NonNull.class, null, mData); diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 50dd7a0bc1be..6ae71d2bb25e 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -1409,9 +1409,10 @@ public final class DisplayManager { * @param hdrConversionMode The {@link HdrConversionMode} to set. * Note, {@code HdrConversionMode.preferredHdrOutputType} is only applicable when * {@code HdrConversionMode.conversionMode} is {@link HdrConversionMode#HDR_CONVERSION_FORCE}. + * If {@code HdrConversionMode.preferredHdrOutputType} is not set in case when + * {@code HdrConversionMode.conversionMode} is {@link HdrConversionMode#HDR_CONVERSION_FORCE}, + * it means that preferred output type is SDR. * - * @throws IllegalArgumentException if hdrConversionMode.preferredHdrOutputType is not set - * when hdrConversionMode.conversionMode is {@link HdrConversionMode#HDR_CONVERSION_FORCE}. * @throws IllegalArgumentException if hdrConversionMode.preferredHdrOutputType is set but * hdrConversionMode.conversionMode is not {@link HdrConversionMode#HDR_CONVERSION_FORCE}. * diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index 6b56a067a198..067ae4d438cc 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -27,13 +27,13 @@ import android.media.projection.MediaProjection; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; +import android.util.ArraySet; import android.view.Display; import android.view.Surface; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; import java.util.Objects; +import java.util.Set; /** * Holds configuration used to create {@link VirtualDisplay} instances. @@ -51,8 +51,8 @@ public final class VirtualDisplayConfig implements Parcelable { private final Surface mSurface; private final String mUniqueId; private final int mDisplayIdToMirror; - private final boolean mWindowManagerMirroring; - private ArrayList<String> mDisplayCategories = null; + private final boolean mWindowManagerMirroringEnabled; + private ArraySet<String> mDisplayCategories = null; private final float mRequestedRefreshRate; private VirtualDisplayConfig( @@ -64,8 +64,8 @@ public final class VirtualDisplayConfig implements Parcelable { @Nullable Surface surface, @Nullable String uniqueId, int displayIdToMirror, - boolean windowManagerMirroring, - @NonNull ArrayList<String> displayCategories, + boolean windowManagerMirroringEnabled, + @NonNull ArraySet<String> displayCategories, float requestedRefreshRate) { mName = name; mWidth = width; @@ -75,7 +75,7 @@ public final class VirtualDisplayConfig implements Parcelable { mSurface = surface; mUniqueId = uniqueId; mDisplayIdToMirror = displayIdToMirror; - mWindowManagerMirroring = windowManagerMirroring; + mWindowManagerMirroringEnabled = windowManagerMirroringEnabled; mDisplayCategories = displayCategories; mRequestedRefreshRate = requestedRefreshRate; } @@ -151,8 +151,8 @@ public final class VirtualDisplayConfig implements Parcelable { * if DisplayManager should record contents instead. * @hide */ - public boolean isWindowManagerMirroring() { - return mWindowManagerMirroring; + public boolean isWindowManagerMirroringEnabled() { + return mWindowManagerMirroringEnabled; } /** @@ -161,8 +161,8 @@ public final class VirtualDisplayConfig implements Parcelable { * @see Builder#setDisplayCategories */ @NonNull - public List<String> getDisplayCategories() { - return Collections.unmodifiableList(mDisplayCategories); + public Set<String> getDisplayCategories() { + return Collections.unmodifiableSet(mDisplayCategories); } /** @@ -185,8 +185,8 @@ public final class VirtualDisplayConfig implements Parcelable { dest.writeTypedObject(mSurface, flags); dest.writeString8(mUniqueId); dest.writeInt(mDisplayIdToMirror); - dest.writeBoolean(mWindowManagerMirroring); - dest.writeStringList(mDisplayCategories); + dest.writeBoolean(mWindowManagerMirroringEnabled); + dest.writeArraySet(mDisplayCategories); dest.writeFloat(mRequestedRefreshRate); } @@ -210,7 +210,7 @@ public final class VirtualDisplayConfig implements Parcelable { && Objects.equals(mSurface, that.mSurface) && Objects.equals(mUniqueId, that.mUniqueId) && mDisplayIdToMirror == that.mDisplayIdToMirror - && mWindowManagerMirroring == that.mWindowManagerMirroring + && mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled && Objects.equals(mDisplayCategories, that.mDisplayCategories) && mRequestedRefreshRate == that.mRequestedRefreshRate; } @@ -219,7 +219,7 @@ public final class VirtualDisplayConfig implements Parcelable { public int hashCode() { int hashCode = Objects.hash( mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, - mDisplayIdToMirror, mWindowManagerMirroring, mDisplayCategories, + mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, mRequestedRefreshRate); return hashCode; } @@ -236,7 +236,7 @@ public final class VirtualDisplayConfig implements Parcelable { + " mSurface=" + mSurface + " mUniqueId=" + mUniqueId + " mDisplayIdToMirror=" + mDisplayIdToMirror - + " mWindowManagerMirroring=" + mWindowManagerMirroring + + " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled + " mDisplayCategories=" + mDisplayCategories + " mRequestedRefreshRate=" + mRequestedRefreshRate + ")"; @@ -251,9 +251,8 @@ public final class VirtualDisplayConfig implements Parcelable { mSurface = in.readTypedObject(Surface.CREATOR); mUniqueId = in.readString8(); mDisplayIdToMirror = in.readInt(); - mWindowManagerMirroring = in.readBoolean(); - mDisplayCategories = new ArrayList<>(); - in.readStringList(mDisplayCategories); + mWindowManagerMirroringEnabled = in.readBoolean(); + mDisplayCategories = (ArraySet<String>) in.readArraySet(null); mRequestedRefreshRate = in.readFloat(); } @@ -283,8 +282,8 @@ public final class VirtualDisplayConfig implements Parcelable { private Surface mSurface = null; private String mUniqueId = null; private int mDisplayIdToMirror = DEFAULT_DISPLAY; - private boolean mWindowManagerMirroring = false; - private ArrayList<String> mDisplayCategories = new ArrayList<>(); + private boolean mWindowManagerMirroringEnabled = false; + private ArraySet<String> mDisplayCategories = new ArraySet<>(); private float mRequestedRefreshRate = 0.0f; /** @@ -370,8 +369,8 @@ public final class VirtualDisplayConfig implements Parcelable { * @hide */ @NonNull - public Builder setWindowManagerMirroring(boolean windowManagerMirroring) { - mWindowManagerMirroring = windowManagerMirroring; + public Builder setWindowManagerMirroringEnabled(boolean windowManagerMirroringEnabled) { + mWindowManagerMirroringEnabled = windowManagerMirroringEnabled; return this; } @@ -383,7 +382,7 @@ public final class VirtualDisplayConfig implements Parcelable { * {@link android.content.pm.ActivityInfo#requiredDisplayCategory}. */ @NonNull - public Builder setDisplayCategories(@NonNull List<String> displayCategories) { + public Builder setDisplayCategories(@NonNull Set<String> displayCategories) { mDisplayCategories.clear(); mDisplayCategories.addAll(Objects.requireNonNull(displayCategories)); return this; @@ -435,7 +434,7 @@ public final class VirtualDisplayConfig implements Parcelable { mSurface, mUniqueId, mDisplayIdToMirror, - mWindowManagerMirroring, + mWindowManagerMirroringEnabled, mDisplayCategories, mRequestedRefreshRate); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index a33cd9760091..490589f34411 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -48,8 +48,6 @@ import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.ServiceManager.ServiceNotFoundException; import android.os.SystemClock; import android.os.VibrationEffect; import android.os.Vibrator; @@ -305,8 +303,11 @@ public final class InputManager { private static String sVelocityTrackerStrategy; - private InputManager(IInputManager im) { - mIm = im; + private InputManagerGlobal mGlobal; + + private InputManager() { + mGlobal = InputManagerGlobal.getInstance(); + mIm = mGlobal.getInputManagerService(); try { sVelocityTrackerStrategy = mIm.getVelocityTrackerStrategy(); } catch (RemoteException ex) { @@ -324,7 +325,8 @@ public final class InputManager { @VisibleForTesting public static InputManager resetInstance(IInputManager inputManagerService) { synchronized (InputManager.class) { - sInstance = new InputManager(inputManagerService); + InputManagerGlobal.resetInstance(inputManagerService); + sInstance = new InputManager(); return sInstance; } } @@ -337,6 +339,7 @@ public final class InputManager { @VisibleForTesting public static void clearInstance() { synchronized (InputManager.class) { + InputManagerGlobal.clearInstance(); sInstance = null; } } @@ -364,13 +367,7 @@ public final class InputManager { public static InputManager getInstance(Context context) { synchronized (InputManager.class) { if (sInstance == null) { - try { - sInstance = new InputManager(IInputManager.Stub - .asInterface(ServiceManager.getServiceOrThrow(Context.INPUT_SERVICE))); - - } catch (ServiceNotFoundException e) { - throw new IllegalStateException(e); - } + sInstance = new InputManager(); } if (sInstance.mWeakContext == null || sInstance.mWeakContext.get() == null) { sInstance.mWeakContext = new WeakReference(context); diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java new file mode 100644 index 000000000000..82dddfc8756c --- /dev/null +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +import android.content.Context; +import android.os.IBinder; +import android.os.ServiceManager; + +/** + * Manages communication with the input manager service on behalf of + * an application process. You're probably looking for {@link InputManager}. + * + * @hide + */ +public final class InputManagerGlobal { + private static final String TAG = "InputManagerGlobal"; + + private static InputManagerGlobal sInstance; + + private final IInputManager mIm; + + public InputManagerGlobal(IInputManager im) { + mIm = im; + } + + /** + * Gets an instance of the input manager global singleton. + * + * @return The display manager instance, may be null early in system startup + * before the display manager has been fully initialized. + */ + public static InputManagerGlobal getInstance() { + synchronized (InputManagerGlobal.class) { + if (sInstance == null) { + IBinder b = ServiceManager.getService(Context.INPUT_SERVICE); + if (b != null) { + sInstance = new InputManagerGlobal(IInputManager.Stub.asInterface(b)); + } + } + return sInstance; + } + } + + public IInputManager getInputManagerService() { + return mIm; + } + + /** + * Gets an instance of the input manager. + * + * @return The input manager instance. + */ + public static InputManagerGlobal resetInstance(IInputManager inputManagerService) { + synchronized (InputManager.class) { + sInstance = new InputManagerGlobal(inputManagerService); + return sInstance; + } + } + + /** + * Clear the instance of the input manager. + */ + public static void clearInstance() { + synchronized (InputManagerGlobal.class) { + sInstance = null; + } + } +} diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 9341105675a2..104a8b2095d8 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -475,8 +475,8 @@ public class NetworkPolicyManager { * * @param uid The UID whose status needs to be checked. * @return {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_DISABLED}, - * {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_ENABLED}, - * or {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote + * {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_ENABLED}, + * or {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote * the current status of the UID. * @hide */ @@ -769,6 +769,28 @@ public class NetworkPolicyManager { } /** + * Returns the default network capabilities + * ({@link ActivityManager#PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK + * ActivityManager.PROCESS_CAPABILITY_*}) of the specified process state. + * This <b>DOES NOT</b> return all default process capabilities for a proc state. + * @hide + */ + public static int getDefaultProcessNetworkCapabilities(int procState) { + switch (procState) { + case ActivityManager.PROCESS_STATE_PERSISTENT: + case ActivityManager.PROCESS_STATE_PERSISTENT_UI: + case ActivityManager.PROCESS_STATE_TOP: + return ActivityManager.PROCESS_CAPABILITY_ALL; + case ActivityManager.PROCESS_STATE_BOUND_TOP: + case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE: + case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE: + return ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; + default: + return ActivityManager.PROCESS_CAPABILITY_NONE; + } + } + + /** * Returns true if {@param procState} is considered foreground and as such will be allowed * to access network when the device is idle or in battery saver mode. Otherwise, false. * @hide @@ -784,7 +806,7 @@ public class NetworkPolicyManager { public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode( int procState, @ProcessCapability int capability) { return procState <= FOREGROUND_THRESHOLD_STATE - || (capability & ActivityManager.PROCESS_CAPABILITY_NETWORK) != 0; + || (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0; } /** @hide */ diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index e2af9b03d7f5..cacde7f4a547 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -26,6 +26,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.app.Activity; +import android.app.ActivityThread; +import android.app.OnActivityPausedListener; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -420,6 +422,7 @@ public final class NfcAdapter { // Guarded by NfcAdapter.class static boolean sIsInitialized = false; static boolean sHasNfcFeature; + static boolean sHasCeFeature; // Final after first constructor, except for // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort @@ -616,11 +619,13 @@ public final class NfcAdapter { PackageManager pm; pm = context.getPackageManager(); sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC); - boolean hasHceFeature = + sHasCeFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) - || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF); + || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF) + || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC) + || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE); /* is this device meant to have NFC */ - if (!sHasNfcFeature && !hasHceFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { Log.v(TAG, "this device does not have NFC support"); throw new UnsupportedOperationException(); } @@ -643,7 +648,7 @@ public final class NfcAdapter { throw new UnsupportedOperationException(); } } - if (hasHceFeature) { + if (sHasCeFeature) { try { sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface(); } catch (RemoteException e) { @@ -1467,11 +1472,17 @@ public final class NfcAdapter { if (activity == null || intent == null) { throw new NullPointerException(); } + if (!activity.isResumed()) { + throw new IllegalStateException("Foreground dispatch can only be enabled " + + "when your activity is resumed"); + } try { TechListParcel parcel = null; if (techLists != null && techLists.length > 0) { parcel = new TechListParcel(techLists); } + ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity, + mForegroundDispatchListener); sService.setForegroundDispatch(intent, filters, parcel); } catch (RemoteException e) { attemptDeadServiceRecovery(e); @@ -1499,8 +1510,25 @@ public final class NfcAdapter { throw new UnsupportedOperationException(); } } + ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, + mForegroundDispatchListener); + disableForegroundDispatchInternal(activity, false); + } + + OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() { + @Override + public void onPaused(Activity activity) { + disableForegroundDispatchInternal(activity, true); + } + }; + + void disableForegroundDispatchInternal(Activity activity, boolean force) { try { sService.setForegroundDispatch(null, null, null); + if (!force && !activity.isResumed()) { + throw new IllegalStateException("You must disable foreground dispatching " + + "while your activity is still resumed"); + } } catch (RemoteException e) { attemptDeadServiceRecovery(e); } @@ -1669,7 +1697,7 @@ public final class NfcAdapter { @SystemApi @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean enable) { - if (!sHasNfcFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } try { @@ -1694,10 +1722,13 @@ public final class NfcAdapter { * Checks if the device supports Secure NFC functionality. * * @return True if device supports Secure NFC, false otherwise - * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if FEATURE_NFC, + * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, + * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE + * are unavailable */ public boolean isSecureNfcSupported() { - if (!sHasNfcFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } try { @@ -1723,11 +1754,14 @@ public final class NfcAdapter { * such as their relative positioning on the device. * * @return Information on the nfc antenna(s) on the device. - * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if FEATURE_NFC, + * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, + * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE + * are unavailable */ @Nullable public NfcAntennaInfo getNfcAntennaInfo() { - if (!sHasNfcFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } try { @@ -1752,12 +1786,15 @@ public final class NfcAdapter { * Checks Secure NFC feature is enabled. * * @return True if Secure NFC is enabled, false otherwise - * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if FEATURE_NFC, + * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, + * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE + * are unavailable * @throws UnsupportedOperationException if device doesn't support * Secure NFC functionality. {@link #isSecureNfcSupported} */ public boolean isSecureNfcEnabled() { - if (!sHasNfcFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } try { @@ -2071,14 +2108,17 @@ public final class NfcAdapter { * always on. * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is * disabled), if false the NFCC will follow completely the Nfc adapter state. - * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if FEATURE_NFC, + * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, + * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE + * are unavailable * @return void * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean value) { - if (!sHasNfcFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } try { @@ -2103,7 +2143,10 @@ public final class NfcAdapter { * Checks NFC controller always on feature is enabled. * * @return True if NFC controller always on is enabled, false otherwise - * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if FEATURE_NFC, + * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, + * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE + * are unavailable * @hide */ @SystemApi @@ -2131,13 +2174,16 @@ public final class NfcAdapter { * Checks if the device supports NFC controller always on functionality. * * @return True if device supports NFC controller always on, false otherwise - * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if FEATURE_NFC, + * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, + * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE + * are unavailable * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported() { - if (!sHasNfcFeature) { + if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } try { diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 3cf3ea234d30..fcebb455d09d 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -117,6 +117,7 @@ interface IUserManager { boolean someUserHasAccount(in String accountName, in String accountType); String getProfileType(int userId); boolean isDemoUser(int userId); + boolean isAdminUser(int userId); boolean isPreCreated(int userId); UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags, int userId, in String[] disallowedPackages); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 8d8deaa28df1..290f929d699a 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2433,21 +2433,24 @@ public class UserManager { } /** - * Used to check if the context user is an admin user. An admin user is allowed to + * Used to check if the context user is an admin user. An admin user may be allowed to * modify or configure certain settings that aren't available to non-admin users, * create and delete additional users, etc. There can be more than one admin users. * * @return whether the context user is an admin user. - * @hide */ - @SystemApi - @RequiresPermission(anyOf = { - Manifest.permission.MANAGE_USERS, - Manifest.permission.CREATE_USERS, - Manifest.permission.QUERY_USERS}) - @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU) + @UserHandleAware( + enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU, + requiresAnyOfPermissionsIfNotCallerProfileGroup = { + Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS, + Manifest.permission.QUERY_USERS}) public boolean isAdminUser() { - return isUserAdmin(getContextUserIfAppropriate()); + try { + return mService.isAdminUser(getContextUserIfAppropriate()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } /** @@ -3972,6 +3975,9 @@ public class UserManager { * time, the preferred user name and account information are used by the setup process for that * user. * + * This API should only be called if the current user is an {@link #isAdminUser() admin} user, + * as otherwise the returned intent will not be able to create a user. + * * @param userName Optional name to assign to the user. * @param accountName Optional account name that will be used by the setup wizard to initialize * the user. diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 07d500176fe5..5b527c70b4f7 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -979,6 +979,19 @@ public abstract class DocumentsProvider extends ContentProvider { } /** + * An unrestricted version of getType, which does not reveal sensitive information + */ + @Override + public final @Nullable String getTypeAnonymous(@NonNull Uri uri) { + switch (mMatcher.match(uri)) { + case MATCH_ROOT: + return DocumentsContract.Root.MIME_TYPE_ITEM; + default: + return null; + } + } + + /** * Implementation is provided by the parent class. Can be overridden to * provide additional functionality, but subclasses <em>must</em> always * call the superclass. If the superclass returns {@code null}, the subclass diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d7cd61567cc7..045ba1f82b7c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5678,6 +5678,36 @@ public final class Settings { public static final String LOCALE_PREFERENCES = "locale_preferences"; /** + * Setting to enable camera flash notification feature. + * <ul> + * <li> 0 = Off + * <li> 1 = On + * </ul> + * @hide + */ + public static final String CAMERA_FLASH_NOTIFICATION = "camera_flash_notification"; + + /** + * Setting to enable screen flash notification feature. + * <ul> + * <li> 0 = Off + * <li> 1 = On + * </ul> + * @hide + */ + public static final String SCREEN_FLASH_NOTIFICATION = "screen_flash_notification"; + + /** + * Integer property that specifes the color for screen flash notification as a + * packed 32-bit color. + * + * @see android.graphics.Color#argb + * @hide + */ + public static final String SCREEN_FLASH_NOTIFICATION_COLOR = + "screen_flash_notification_color_global"; + + /** * IMPORTANT: If you add a new public settings you also have to add it to * PUBLIC_SETTINGS below. If the new setting is hidden you have to add * it to PRIVATE_SETTINGS below. Also add a validator that can validate @@ -5810,6 +5840,9 @@ public final class Settings { PRIVATE_SETTINGS.add(TOUCHPAD_NATURAL_SCROLLING); PRIVATE_SETTINGS.add(TOUCHPAD_TAP_TO_CLICK); PRIVATE_SETTINGS.add(TOUCHPAD_RIGHT_CLICK_ZONE); + PRIVATE_SETTINGS.add(CAMERA_FLASH_NOTIFICATION); + PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION); + PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION_COLOR); } /** @@ -8289,6 +8322,15 @@ public final class Settings { "accessibility_display_inversion_enabled"; /** + * Flag that specifies whether font size has been changed. The flag will + * be set when users change the scaled value of font size for the first time. + * @hide + */ + @Readable + public static final String ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED = + "accessibility_font_scaling_has_been_changed"; + + /** * Setting that specifies whether display color space adjustment is * enabled. * diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index d943bf9ac872..0ef8bb64acaf 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -29,6 +29,7 @@ import android.content.IntentSender; import android.os.Parcel; import android.os.Parcelable; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.widget.RemoteViews; @@ -283,24 +284,28 @@ public final class Dataset implements Parcelable { } /** @hide */ - public RemoteViews getFieldPresentation(int index) { + @TestApi + public @Nullable RemoteViews getFieldPresentation(int index) { final RemoteViews customPresentation = mFieldPresentations.get(index); return customPresentation != null ? customPresentation : mPresentation; } /** @hide */ - public RemoteViews getFieldDialogPresentation(int index) { + @TestApi + public @Nullable RemoteViews getFieldDialogPresentation(int index) { final RemoteViews customPresentation = mFieldDialogPresentations.get(index); return customPresentation != null ? customPresentation : mDialogPresentation; } /** @hide */ + @TestApi public @Nullable InlinePresentation getFieldInlinePresentation(int index) { final InlinePresentation inlinePresentation = mFieldInlinePresentations.get(index); return inlinePresentation != null ? inlinePresentation : mInlinePresentation; } /** @hide */ + @TestApi public @Nullable InlinePresentation getFieldInlineTooltipPresentation(int index) { final InlinePresentation inlineTooltipPresentation = mFieldInlineTooltipPresentations.get(index); @@ -309,6 +314,7 @@ public final class Dataset implements Parcelable { } /** @hide */ + @TestApi public @Nullable DatasetFieldFilter getFilter(int index) { return mFieldFilters.get(index); } @@ -389,6 +395,9 @@ public final class Dataset implements Parcelable { if (mAuthentication != null) { builder.append(", hasAuthentication"); } + if (mAutofillDatatypes != null) { + builder.append(", autofillDatatypes=").append(mAutofillDatatypes); + } return builder.append(']').toString(); } @@ -1090,8 +1099,7 @@ public final class Dataset implements Parcelable { * * @return this builder. */ - public @NonNull Dataset.Builder setField( - @NonNull String hint, @NonNull Field field) { + public @NonNull Dataset.Builder setField(@NonNull String hint, @NonNull Field field) { throwIfDestroyed(); final DatasetFieldFilter filter = field.getDatasetFieldFilter(); @@ -1111,6 +1119,23 @@ public final class Dataset implements Parcelable { } /** + * Adds a field to this Dataset that is relevant to all applicable hints. This is used to + * provide field information when autofill with platform detections is enabled. + * Platform detections are on when receiving a populated list from + * FillRequest#getHints(). + * + * @param field the fill information about the field. + * + * @throws IllegalStateException if {@link #build()} was already called + * or this builder also contains AutofillId information + * + * @return this builder. + */ + public @NonNull Dataset.Builder setFieldForAllHints(@NonNull Field field) { + return setField(AutofillManager.ANY_HINT, field); + } + + /** * Sets the value of a field with an <a href="#Filtering">explicit filter</a>, and using an * {@link InlinePresentation} to visualize it as an inline suggestion. * @@ -1304,7 +1329,7 @@ public final class Dataset implements Parcelable { parcel.createTypedArrayList(InlinePresentation.CREATOR); final ArrayList<DatasetFieldFilter> filters = parcel.createTypedArrayList(DatasetFieldFilter.CREATOR); - final ArrayList<String> datatypes = + final ArrayList<String> autofillDatatypes = parcel.createStringArrayList(); final ClipData fieldContent = parcel.readParcelable(null, android.content.ClipData.class); @@ -1341,9 +1366,9 @@ public final class Dataset implements Parcelable { } final int inlinePresentationsSize = inlinePresentations.size(); - if (ids.size() == 0 && datatypes.size() > 0) { - for (int i = 0; i < ids.size(); i++) { - final String datatype = datatypes.get(i); + if (ids.size() == 0 && autofillDatatypes.size() > 0) { + for (int i = 0; i < autofillDatatypes.size(); i++) { + final String datatype = autofillDatatypes.get(i); final AutofillValue value = values.get(i); final RemoteViews fieldPresentation = presentations.get(i); final RemoteViews fieldDialogPresentation = dialogPresentations.get(i); @@ -1393,8 +1418,10 @@ public final class Dataset implements Parcelable { * * @hide */ + @TestApi public static final class DatasetFieldFilter implements Parcelable { + /** @hide */ @Nullable public final Pattern pattern; @@ -1402,6 +1429,10 @@ public final class Dataset implements Parcelable { this.pattern = pattern; } + public @Nullable Pattern getPattern() { + return pattern; + } + @Override public String toString() { if (!sDebug) return super.toString(); @@ -1416,7 +1447,7 @@ public final class Dataset implements Parcelable { } @Override - public void writeToParcel(Parcel parcel, int flags) { + public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeSerializable(pattern); } diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index b0e847cd53f9..5d58120ef5bb 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -233,6 +233,22 @@ public final class FillEventHistory implements Parcelable { */ public static final int TYPE_DATASETS_SHOWN = 5; + /** + * The app/user requested for a field to be Autofilled. + * + * This event is fired when the view has been entered (by user or app) in order + * to differentiate from FillRequests that have been pretriggered for FillDialogs. + * + * For example, the user might navigate away from a screen without tapping any + * fields. In this case, a FillRequest/FillResponse has been generated, but was + * not used for Autofilling. The user did not intend to see an Autofill result, + * but a FillRequest was still generated. This is different from when the user + * did tap on a field after the pretriggered FillRequest, this event will appear + * in the FillEventHistory, signaling that the user did intend to Autofill + * something. + */ + public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; + /** @hide */ @IntDef(prefix = { "TYPE_" }, value = { TYPE_DATASET_SELECTED, @@ -240,7 +256,8 @@ public final class FillEventHistory implements Parcelable { TYPE_AUTHENTICATION_SELECTED, TYPE_SAVE_SHOWN, TYPE_CONTEXT_COMMITTED, - TYPE_DATASETS_SHOWN + TYPE_DATASETS_SHOWN, + TYPE_VIEW_REQUESTED_AUTOFILL }) @Retention(RetentionPolicy.SOURCE) @interface EventIds{} @@ -659,8 +676,8 @@ public final class FillEventHistory implements Parcelable { @Nullable AutofillId[] detectedFieldIds, @Nullable FieldClassification[] detectedFieldClassifications, int saveDialogNotShowReason, int uiType) { - mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN, - "eventType"); + mEventType = Preconditions.checkArgumentInRange(eventType, 0, + TYPE_VIEW_REQUESTED_AUTOFILL, "eventType"); mDatasetId = datasetId; mClientState = clientState; mSelectedDatasetIds = selectedDatasetIds; @@ -723,6 +740,8 @@ public final class FillEventHistory implements Parcelable { return "TYPE_CONTEXT_COMMITTED"; case TYPE_DATASETS_SHOWN: return "TYPE_DATASETS_SHOWN"; + case TYPE_VIEW_REQUESTED_AUTOFILL: + return "TYPE_VIEW_REQUESTED_AUTOFILL"; default: return "TYPE_UNKNOWN"; } diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java index f0f954dda182..cd53cb6afc71 100644 --- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java +++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java @@ -16,8 +16,10 @@ package android.service.credentials; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.os.Parcel; import android.os.Parcelable; @@ -32,7 +34,7 @@ import java.util.Objects; */ public final class BeginCreateCredentialResponse implements Parcelable { private final @NonNull List<CreateEntry> mCreateEntries; - private final @Nullable CreateEntry mRemoteCreateEntry; + private final @Nullable RemoteEntry mRemoteCreateEntry; /** * Creates an empty response instance, to be used when there are no {@link CreateEntry} @@ -46,7 +48,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { List<CreateEntry> createEntries = new ArrayList<>(); in.readTypedList(createEntries, CreateEntry.CREATOR); mCreateEntries = createEntries; - mRemoteCreateEntry = in.readTypedObject(CreateEntry.CREATOR); + mRemoteCreateEntry = in.readTypedObject(RemoteEntry.CREATOR); } @Override @@ -75,7 +77,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { /* package-private */ BeginCreateCredentialResponse( @NonNull List<CreateEntry> createEntries, - @Nullable CreateEntry remoteCreateEntry) { + @Nullable RemoteEntry remoteCreateEntry) { this.mCreateEntries = createEntries; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mCreateEntries); @@ -88,7 +90,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { } /** Returns the remote create entry to be displayed on the UI. */ - public @Nullable CreateEntry getRemoteCreateEntry() { + public @Nullable RemoteEntry getRemoteCreateEntry() { return mRemoteCreateEntry; } @@ -98,7 +100,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { @SuppressWarnings("WeakerAccess") /* synthetic access */ public static final class Builder { private @NonNull List<CreateEntry> mCreateEntries = new ArrayList<>(); - private @Nullable CreateEntry mRemoteCreateEntry; + private @Nullable RemoteEntry mRemoteCreateEntry; /** * Sets the list of create entries to be shown on the UI. @@ -137,8 +139,18 @@ public final class BeginCreateCredentialResponse implements Parcelable { * result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE} key should be populated * with a {@link android.credentials.CreateCredentialResponse} object. + * + * <p> Note that as a provider service you will only be able to set a remote entry if : + * - Provider service possesses the + * {@link Manifest.permission.PROVIDE_REMOTE_CREDENTIALS} permission. + * - Provider service is configured as the provider that can provide remote entries. + * + * If the above conditions are not met, setting back {@link BeginCreateCredentialResponse} + * on the callback from {@link CredentialProviderService#onBeginCreateCredential} + * will throw a {@link SecurityException}. */ - public @NonNull Builder setRemoteCreateEntry(@Nullable CreateEntry remoteCreateEntry) { + @RequiresPermission(Manifest.permission.PROVIDE_REMOTE_CREDENTIALS) + public @NonNull Builder setRemoteCreateEntry(@Nullable RemoteEntry remoteCreateEntry) { mRemoteCreateEntry = remoteCreateEntry; return this; } diff --git a/core/java/android/service/credentials/BeginGetCredentialResponse.java b/core/java/android/service/credentials/BeginGetCredentialResponse.java index 3652742d4ff4..e25b6869605d 100644 --- a/core/java/android/service/credentials/BeginGetCredentialResponse.java +++ b/core/java/android/service/credentials/BeginGetCredentialResponse.java @@ -16,8 +16,10 @@ package android.service.credentials; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.os.Parcel; import android.os.Parcelable; @@ -42,7 +44,7 @@ public final class BeginGetCredentialResponse implements Parcelable { private final @NonNull List<Action> mActions; /** Remote credential entry to get the response from a different device. */ - private final @Nullable CredentialEntry mRemoteCredentialEntry; + private final @Nullable RemoteEntry mRemoteCredentialEntry; /** * Creates an empty response instance, to be used when there are no {@link CredentialEntry}, @@ -57,7 +59,7 @@ public final class BeginGetCredentialResponse implements Parcelable { private BeginGetCredentialResponse(@NonNull List<CredentialEntry> credentialEntries, @NonNull List<Action> authenticationEntries, @NonNull List<Action> actions, - @Nullable CredentialEntry remoteCredentialEntry) { + @Nullable RemoteEntry remoteCredentialEntry) { mCredentialEntries = new ArrayList<>(credentialEntries); mAuthenticationEntries = new ArrayList<>(authenticationEntries); mActions = new ArrayList<>(actions); @@ -74,7 +76,7 @@ public final class BeginGetCredentialResponse implements Parcelable { List<Action> actions = new ArrayList<>(); in.readTypedList(actions, Action.CREATOR); mActions = actions; - mRemoteCredentialEntry = in.readTypedObject(CredentialEntry.CREATOR); + mRemoteCredentialEntry = in.readTypedObject(RemoteEntry.CREATOR); } public static final @NonNull Creator<BeginGetCredentialResponse> CREATOR = @@ -127,7 +129,7 @@ public final class BeginGetCredentialResponse implements Parcelable { /** * Returns the remote credential entry to be displayed on the UI. */ - public @Nullable CredentialEntry getRemoteCredentialEntry() { + public @Nullable RemoteEntry getRemoteCredentialEntry() { return mRemoteCredentialEntry; } @@ -139,7 +141,7 @@ public final class BeginGetCredentialResponse implements Parcelable { private List<Action> mAuthenticationEntries = new ArrayList<>(); private List<Action> mActions = new ArrayList<>(); - private CredentialEntry mRemoteCredentialEntry; + private RemoteEntry mRemoteCredentialEntry; /** * Sets a remote credential entry to be shown on the UI. Provider must set this if they @@ -154,8 +156,18 @@ public final class BeginGetCredentialResponse implements Parcelable { * result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} key should be populated * with a {@link android.credentials.Credential} object. + * + * <p> Note that as a provider service you will only be able to set a remote entry if : + * - Provider service possesses the + * {@link Manifest.permission.PROVIDE_REMOTE_CREDENTIALS} permission. + * - Provider service is configured as the provider that can provide remote entries. + * + * If the above conditions are not met, setting back {@link BeginGetCredentialResponse} + * on the callback from {@link CredentialProviderService#onBeginGetCredential} will + * throw a {@link SecurityException}. */ - public @NonNull Builder setRemoteCredentialEntry(@Nullable CredentialEntry + @RequiresPermission(Manifest.permission.PROVIDE_REMOTE_CREDENTIALS) + public @NonNull Builder setRemoteCredentialEntry(@Nullable RemoteEntry remoteCredentialEntry) { mRemoteCredentialEntry = remoteCredentialEntry; return this; diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java index 7e98bc7eb975..85eac6edb6d2 100644 --- a/core/java/android/service/credentials/CredentialEntry.java +++ b/core/java/android/service/credentials/CredentialEntry.java @@ -27,6 +27,8 @@ import android.credentials.GetCredentialResponse; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.Preconditions; + /** * A credential entry that is to be displayed on the account selector that is presented to the * user. @@ -56,7 +58,7 @@ import android.os.Parcelable; @SuppressLint("ParcelNotFinal") public class CredentialEntry implements Parcelable { /** The request option that corresponds to this entry. **/ - private final @Nullable BeginGetCredentialOption mBeginGetCredentialOption; + private final @Nullable String mBeginGetCredentialOptionId; /** The type of the credential entry to be shown on the UI. */ private final @NonNull String mType; @@ -72,19 +74,51 @@ public class CredentialEntry implements Parcelable { * to respond to query phase {@link CredentialProviderService#onBeginGetCredential} * credential retrieval requests. * + * @param beginGetCredentialOptionId the beginGetCredentialOptionId to be retrieved from + * {@link BeginGetCredentialOption#getId()} - the request option for which this CredentialEntry + * is being constructed This helps maintain an association + * such that when the user selects this entry, providers can + * receive the complete corresponding + * {@link GetCredentialRequest}. + * @param type the type of the credential for which this credential entry is being created + * @param slice the slice containing the metadata to be shown on the UI. Must be + * constructed through the androidx.credentials jetpack library. + * + * @throws IllegalArgumentException If {@code beginGetCredentialOptionId} or {@code type} + * is null, or empty + */ + public CredentialEntry(@NonNull String beginGetCredentialOptionId, @NonNull String type, + @NonNull Slice slice) { + mBeginGetCredentialOptionId = Preconditions.checkStringNotEmpty( + beginGetCredentialOptionId, "beginGetCredentialOptionId must not be " + + "null, or empty"); + mType = Preconditions.checkStringNotEmpty(type, "type must not be null, or " + + "empty"); + mSlice = requireNonNull(slice, "slice must not be null"); + } + + /** + * Creates an entry that is associated with a {@link BeginGetCredentialOption} request. + * Providers must use this constructor when they extend from {@link CredentialProviderService} + * to respond to query phase {@link CredentialProviderService#onBeginGetCredential} + * credential retrieval requests. + * * @param beginGetCredentialOption the request option for which this credential entry is * being constructed This helps maintain an association, * such that when the user selects this entry, providers - * can receive the conmplete corresponding request. + * can receive the complete corresponding request. * @param slice the slice containing the metadata to be shown on the UI. Must be * constructed through the androidx.credentials jetpack library. */ public CredentialEntry(@NonNull BeginGetCredentialOption beginGetCredentialOption, @NonNull Slice slice) { - mBeginGetCredentialOption = requireNonNull(beginGetCredentialOption, - "beginGetCredentialOption must not be null"); - mType = requireNonNull(mBeginGetCredentialOption.getType(), - "type must not be null"); + requireNonNull(beginGetCredentialOption, "beginGetCredentialOption must not" + + " be null"); + mBeginGetCredentialOptionId = Preconditions.checkStringNotEmpty( + beginGetCredentialOption.getId(), "Id in beginGetCredentialOption " + + "must not be null"); + mType = Preconditions.checkStringNotEmpty(beginGetCredentialOption.getType(), + "type in beginGetCredentialOption must not be null"); mSlice = requireNonNull(slice, "slice must not be null"); } @@ -101,7 +135,7 @@ public class CredentialEntry implements Parcelable { */ // TODO: Unhide this constructor when the registry APIs are stable public CredentialEntry(@NonNull String type, @NonNull Slice slice) { - mBeginGetCredentialOption = null; + mBeginGetCredentialOptionId = null; mType = requireNonNull(type, "type must not be null"); mSlice = requireNonNull(slice, "slice must not be null"); } @@ -110,7 +144,7 @@ public class CredentialEntry implements Parcelable { requireNonNull(in, "parcel must not be null"); mType = in.readString8(); mSlice = in.readTypedObject(Slice.CREATOR); - mBeginGetCredentialOption = in.readTypedObject(BeginGetCredentialOption.CREATOR); + mBeginGetCredentialOptionId = in.readString8(); } @NonNull @@ -136,15 +170,16 @@ public class CredentialEntry implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); dest.writeTypedObject(mSlice, flags); - dest.writeTypedObject(mBeginGetCredentialOption, flags); + dest.writeString8(mBeginGetCredentialOptionId); } /** - * Returns the request option for which this credential entry has been constructed. + * Returns the id of the {@link BeginGetCredentialOption} for which this credential + * entry has been constructed. */ @NonNull - public BeginGetCredentialOption getBeginGetCredentialOption() { - return mBeginGetCredentialOption; + public String getBeginGetCredentialOptionId() { + return mBeginGetCredentialOptionId; } /** diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index d737f6b6cdc8..e88474d86798 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -18,6 +18,7 @@ package android.service.credentials; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import android.Manifest; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.SdkConstant; @@ -218,6 +219,11 @@ public abstract class CredentialProviderService extends Service { GetCredentialException>() { @Override public void onResult(BeginGetCredentialResponse result) { + // If provider service does not possess the HYBRID permission, this + // check will throw an exception in the provider process. + if (result.getRemoteCredentialEntry() != null) { + enforceRemoteEntryPermission(); + } try { callback.onSuccess(result); } catch (RemoteException e) { @@ -236,6 +242,15 @@ public abstract class CredentialProviderService extends Service { )); return transport; } + private void enforceRemoteEntryPermission() { + String permission = + Manifest.permission.PROVIDE_REMOTE_CREDENTIALS; + getApplicationContext().enforceCallingOrSelfPermission( + permission, + String.format("Provider must have %s, in order to set a " + + "remote entry", permission) + ); + } @Override public ICancellationSignal onBeginCreateCredential(BeginCreateCredentialRequest request, @@ -253,6 +268,11 @@ public abstract class CredentialProviderService extends Service { BeginCreateCredentialResponse, CreateCredentialException>() { @Override public void onResult(BeginCreateCredentialResponse result) { + // If provider service does not possess the HYBRID permission, this + // check will throw an exception in the provider process. + if (result.getRemoteCreateEntry() != null) { + enforceRemoteEntryPermission(); + } try { callback.onSuccess(result); } catch (RemoteException e) { diff --git a/core/java/android/service/credentials/GetCredentialRequest.java b/core/java/android/service/credentials/GetCredentialRequest.java index 4f13922caf15..5bad9abb2eed 100644 --- a/core/java/android/service/credentials/GetCredentialRequest.java +++ b/core/java/android/service/credentials/GetCredentialRequest.java @@ -23,14 +23,16 @@ import android.os.Parcelable; import com.android.internal.util.AnnotationValidations; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** * Request for getting user's credential from a given credential provider. * - * <p>Provider will receive this request once the user selects a given {@link CredentialEntry} - * on the selector, that was sourced from provider's result to - * {@link CredentialProviderService#onBeginGetCredential}. + * <p>A credential provider will receive this request once the user selects a + * given {@link CredentialEntry}, or {@link RemoteEntry} on the selector, that was sourced + * from provider's initial response to {@link CredentialProviderService#onBeginGetCredential}. */ public final class GetCredentialRequest implements Parcelable { /** Calling package of the app requesting for credentials. */ @@ -38,24 +40,27 @@ public final class GetCredentialRequest implements Parcelable { private final CallingAppInfo mCallingAppInfo; /** - * Holds parameters to be used for retrieving a specific type of credential. + * Holds a list of options (parameters) to be used for retrieving a specific type of credential. */ @NonNull - private final CredentialOption mCredentialOption; + private final List<CredentialOption> mCredentialOptions; public GetCredentialRequest(@NonNull CallingAppInfo callingAppInfo, - @NonNull CredentialOption credentialOption) { + @NonNull List<CredentialOption> credentialOptions) { this.mCallingAppInfo = Objects.requireNonNull(callingAppInfo, "callingAppInfo must not be null"); - this.mCredentialOption = Objects.requireNonNull(credentialOption, - "credentialOption must not be null"); + this.mCredentialOptions = Objects.requireNonNull(credentialOptions, + "credentialOptions must not be null"); } private GetCredentialRequest(@NonNull Parcel in) { mCallingAppInfo = in.readTypedObject(CallingAppInfo.CREATOR); AnnotationValidations.validate(NonNull.class, null, mCallingAppInfo); - mCredentialOption = in.readTypedObject(CredentialOption.CREATOR); - AnnotationValidations.validate(NonNull.class, null, mCredentialOption); + + List<CredentialOption> credentialOptions = new ArrayList<>(); + in.readTypedList(credentialOptions, CredentialOption.CREATOR); + mCredentialOptions = credentialOptions; + AnnotationValidations.validate(NonNull.class, null, mCredentialOptions); } @NonNull public static final Creator<GetCredentialRequest> CREATOR = @@ -79,7 +84,7 @@ public final class GetCredentialRequest implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeTypedObject(mCallingAppInfo, flags); - dest.writeTypedObject(mCredentialOption, flags); + dest.writeTypedList(mCredentialOptions, flags); } /** @@ -91,10 +96,26 @@ public final class GetCredentialRequest implements Parcelable { } /** - * Returns the parameters needed to return a given type of credential. + * Returns a list of options containing parameters needed to return a given type of credential. + * This is part of the request that the credential provider receives after the user has + * selected an entry on a selector UI. + * + * When the user selects a {@link CredentialEntry} and the credential provider receives a + * {@link GetCredentialRequest}, this list is expected to contain a single + * {@link CredentialOption} only. A {@link CredentialEntry} is always created for a given + * {@link BeginGetCredentialOption}, and hence when the user selects it, the provider + * receives a corresponding {@link CredentialOption} that contains all the required parameters + * to actually retrieve the credential. + * + * When the user selects a {@link RemoteEntry} and the credential provider receives a + * {@link GetCredentialRequest}, this list may contain greater than a single + * {@link CredentialOption}, representing the number of options specified by the developer + * in the original {@link android.credentials.GetCredentialRequest}. This is because a + * {@link RemoteEntry} indicates that the entire request will be processed on a different + * device and is not tied to a particular option. */ @NonNull - public CredentialOption getCredentialOption() { - return mCredentialOption; + public List<CredentialOption> getCredentialOptions() { + return mCredentialOptions; } } diff --git a/core/java/android/service/credentials/RemoteEntry.java b/core/java/android/service/credentials/RemoteEntry.java new file mode 100644 index 000000000000..716c00d726f3 --- /dev/null +++ b/core/java/android/service/credentials/RemoteEntry.java @@ -0,0 +1,97 @@ +/* + * 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 android.service.credentials; + +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.app.PendingIntent; +import android.app.slice.Slice; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * An entry to be shown on the UI. This entry represents remote execution of a get/create flow + * whereby credentials are retrieved from, or stored to a remote device. + * + * <p>If user selects this entry, the corresponding {@link PendingIntent} set on the + * {@code slice} as a {@link androidx.slice.core.SliceAction} will get invoked. + * Once the resulting activity fulfills the required user engagement, + * the {@link android.app.Activity} result should be set to {@link android.app.Activity#RESULT_OK}, + * and the result of the operation must be set as the activity result. + * + * For a get flow, invoked through {@link CredentialProviderService#onBeginGetCredential}, + * providers must set a {@link android.credentials.GetCredentialResponse} on the activity result, + * against the key {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE}. + * + * For a creates flow, invoked through {@link CredentialProviderService#onBeginCreateCredential}, + * providers must set a {@link android.credentials.CreateCredentialResponse} on the activity + * result against the ket {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE}. + * + * <p>Any class that extends this class must only add extra field values to the {@code slice} + * object passed into the constructor. Any other field will not be parceled through. If the + * derived class has custom parceling implementation, this class will not be able to unpack + * the parcel without having access to that implementation. + */ +@SuppressLint("ParcelNotFinal") +public class RemoteEntry implements Parcelable { + private final @NonNull Slice mSlice; + + private RemoteEntry(@NonNull Parcel in) { + mSlice = in.readTypedObject(Slice.CREATOR); + } + + @NonNull + public static final Creator<RemoteEntry> CREATOR = new Creator<RemoteEntry>() { + @Override + public RemoteEntry createFromParcel(@NonNull Parcel in) { + return new RemoteEntry(in); + } + + @Override + public RemoteEntry[] newArray(int size) { + return new RemoteEntry[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mSlice, flags); + } + + /** + * Constructs a RemoteEntry to be displayed on the UI. + * + * @param slice the display content to be displayed on the UI, along with this entry + */ + public RemoteEntry( + @NonNull Slice slice) { + this.mSlice = slice; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSlice); + } + + /** Returns the content to be displayed with this remote entry on the UI. */ + @NonNull + public Slice getSlice() { + return mSlice; + } +} diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java index ff14404f787e..a3892238f1e6 100644 --- a/core/java/android/service/dreams/DreamActivity.java +++ b/core/java/android/service/dreams/DreamActivity.java @@ -70,7 +70,7 @@ public class DreamActivity extends Activity { @Override public void onDestroy() { - if (mCallback != null && !isFinishing()) { + if (mCallback != null) { mCallback.onActivityDestroyed(); } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index d79ea8929047..c7099fdd202a 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -1588,7 +1588,8 @@ public class DreamService extends Service implements Window.Callback { // If DreamActivity is destroyed, wake up from Dream. void onActivityDestroyed() { mActivity = null; - onDestroy(); + mWindow = null; + detach(); } } diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index 0384454bb69c..d9ee859dc66b 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -72,7 +72,7 @@ import java.util.function.IntConsumer; */ @SystemApi public abstract class HotwordDetectionService extends Service - implements SandboxedDetectionServiceBase { + implements SandboxedDetectionInitializer { private static final String TAG = "HotwordDetectionService"; private static final boolean DBG = false; @@ -89,21 +89,23 @@ public abstract class HotwordDetectionService extends Service /** * Indicates that the updated status is successful. * - * @deprecated Replaced with {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_SUCCESS} + * @deprecated Replaced with + * {@link SandboxedDetectionInitializer#INITIALIZATION_STATUS_SUCCESS} */ @Deprecated public static final int INITIALIZATION_STATUS_SUCCESS = - SandboxedDetectionServiceBase.INITIALIZATION_STATUS_SUCCESS; + SandboxedDetectionInitializer.INITIALIZATION_STATUS_SUCCESS; /** * Indicates that the callback wasn’t invoked within the timeout. * This is used by system. * - * @deprecated Replaced with {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_UNKNOWN} + * @deprecated Replaced with + * {@link SandboxedDetectionInitializer#INITIALIZATION_STATUS_UNKNOWN} */ @Deprecated public static final int INITIALIZATION_STATUS_UNKNOWN = - SandboxedDetectionServiceBase.INITIALIZATION_STATUS_UNKNOWN; + SandboxedDetectionInitializer.INITIALIZATION_STATUS_UNKNOWN; /** * Source for the given audio stream. @@ -259,7 +261,7 @@ public abstract class HotwordDetectionService extends Service * * @hide * @deprecated Replaced with - * {@link SandboxedDetectionServiceBase#getMaxCustomInitializationStatus()} + * {@link SandboxedDetectionInitializer#getMaxCustomInitializationStatus()} */ @SystemApi @Deprecated @@ -368,7 +370,7 @@ public abstract class HotwordDetectionService extends Service private void onUpdateStateInternal(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, IRemoteCallback callback) { IntConsumer intConsumer = - SandboxedDetectionServiceBase.createInitializationStatusConsumer(callback); + SandboxedDetectionInitializer.createInitializationStatusConsumer(callback); onUpdateState(options, sharedMemory, UPDATE_TIMEOUT_MILLIS, intConsumer); } diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java index 22d97b7bbcaa..93fcec14cf1c 100644 --- a/core/java/android/service/voice/HotwordDetector.java +++ b/core/java/android/service/voice/HotwordDetector.java @@ -283,9 +283,9 @@ public interface HotwordDetector { * * @param status Info about initialization state of {@link HotwordDetectionService} or * {@link VisualQueryDetectionService}; allowed values are - * {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_SUCCESS}, - * 1<->{@link SandboxedDetectionServiceBase#getMaxCustomInitializationStatus()}, - * {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_UNKNOWN}. + * {@link SandboxedDetectionInitializer#INITIALIZATION_STATUS_SUCCESS}, + * 1<->{@link SandboxedDetectionInitializer#getMaxCustomInitializationStatus()}, + * {@link SandboxedDetectionInitializer#INITIALIZATION_STATUS_UNKNOWN}. */ void onHotwordDetectionServiceInitialized(int status); diff --git a/core/java/android/service/voice/SandboxedDetectionServiceBase.java b/core/java/android/service/voice/SandboxedDetectionInitializer.java index 43331642bd1e..4a41968395a7 100644 --- a/core/java/android/service/voice/SandboxedDetectionServiceBase.java +++ b/core/java/android/service/voice/SandboxedDetectionInitializer.java @@ -28,12 +28,12 @@ import android.os.SharedMemory; import java.util.function.IntConsumer; /** - * Base for all sandboxed detection services, providing a common interface for initialization. + * Provides common initialzation methods for sandboxed detection services. * * @hide */ @SystemApi -public interface SandboxedDetectionServiceBase { +public interface SandboxedDetectionInitializer { /** * Indicates that the updated status is successful. @@ -77,7 +77,7 @@ public interface SandboxedDetectionServiceBase { if (callback != null) { intConsumer = value -> { - if (value > SandboxedDetectionServiceBase + if (value > SandboxedDetectionInitializer .getMaxCustomInitializationStatus()) { throw new IllegalArgumentException( "The initialization status is invalid for " + value); diff --git a/core/java/android/service/voice/VisualQueryDetectionService.java b/core/java/android/service/voice/VisualQueryDetectionService.java index 1783186cd045..cbe7666ddf43 100644 --- a/core/java/android/service/voice/VisualQueryDetectionService.java +++ b/core/java/android/service/voice/VisualQueryDetectionService.java @@ -20,9 +20,11 @@ import android.annotation.DurationMillisLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.Service; import android.content.ContentCaptureOptions; +import android.content.Context; import android.content.Intent; import android.hardware.soundtrigger.SoundTrigger; import android.media.AudioFormat; @@ -35,6 +37,7 @@ import android.os.RemoteException; import android.os.SharedMemory; import android.speech.IRecognitionServiceManager; import android.util.Log; +import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.IContentCaptureManager; import java.util.Objects; @@ -58,7 +61,7 @@ import java.util.function.IntConsumer; */ @SystemApi public abstract class VisualQueryDetectionService extends Service - implements SandboxedDetectionServiceBase { + implements SandboxedDetectionInitializer { private static final String TAG = VisualQueryDetectionService.class.getSimpleName(); @@ -79,6 +82,10 @@ public abstract class VisualQueryDetectionService extends Service public static final String KEY_INITIALIZATION_STATUS = "initialization_status"; private IDetectorSessionVisualQueryDetectionCallback mRemoteCallback = null; + @Nullable + private ContentCaptureManager mContentCaptureManager; + @Nullable + private IRecognitionServiceManager mIRecognitionServiceManager; private final ISandboxedDetectionService mInterface = new ISandboxedDetectionService.Stub() { @@ -139,15 +146,29 @@ public abstract class VisualQueryDetectionService extends Service @Override public void updateContentCaptureManager(IContentCaptureManager manager, ContentCaptureOptions options) { - Log.v(TAG, "Ignore #updateContentCaptureManager"); + mContentCaptureManager = new ContentCaptureManager( + VisualQueryDetectionService.this, manager, options); } @Override public void updateRecognitionServiceManager(IRecognitionServiceManager manager) { - Log.v(TAG, "Ignore #updateRecognitionServiceManager"); + mIRecognitionServiceManager = manager; } }; + @Override + @SuppressLint("OnNameExpected") + public @Nullable Object getSystemService(@ServiceName @NonNull String name) { + if (Context.CONTENT_CAPTURE_MANAGER_SERVICE.equals(name)) { + return mContentCaptureManager; + } else if (Context.SPEECH_RECOGNITION_SERVICE.equals(name) + && mIRecognitionServiceManager != null) { + return mIRecognitionServiceManager.asBinder(); + } else { + return super.getSystemService(name); + } + } + /** * {@inheritDoc} * @hide @@ -175,7 +196,7 @@ public abstract class VisualQueryDetectionService extends Service private void onUpdateStateInternal(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, IRemoteCallback callback) { IntConsumer intConsumer = - SandboxedDetectionServiceBase.createInitializationStatusConsumer(callback); + SandboxedDetectionInitializer.createInitializationStatusConsumer(callback); onUpdateState(options, sharedMemory, UPDATE_TIMEOUT_MILLIS, intConsumer); } diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java index f0f6a4f829cf..7dc0687b549d 100644 --- a/core/java/android/service/voice/VisualQueryDetector.java +++ b/core/java/android/service/voice/VisualQueryDetector.java @@ -201,9 +201,10 @@ public class VisualQueryDetector { * short amount of time to report its initialization state. * * @param status Info about initialization state of {@link VisualQueryDetectionService}; the - * allowed values are {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_SUCCESS}, - * 1<->{@link SandboxedDetectionServiceBase#getMaxCustomInitializationStatus()}, - * {@link SandboxedDetectionServiceBase#INITIALIZATION_STATUS_UNKNOWN}. + * allowed values are + * {@link SandboxedDetectionInitializer#INITIALIZATION_STATUS_SUCCESS}, + * 1<->{@link SandboxedDetectionInitializer#getMaxCustomInitializationStatus()}, + * {@link SandboxedDetectionInitializer#INITIALIZATION_STATUS_UNKNOWN}. */ void onVisualQueryDetectionServiceInitialized(int status); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index f53abce1d1ea..259012f5eb30 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -60,7 +60,6 @@ import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -181,9 +180,6 @@ public abstract class WallpaperService extends Service { private final ArrayMap<IBinder, IWallpaperEngineWrapper> mActiveEngines = new ArrayMap<>(); - private Handler mBackgroundHandler; - private HandlerThread mBackgroundThread; - static final class WallpaperCommand { String action; int x; @@ -202,6 +198,14 @@ public abstract class WallpaperService extends Service { */ public class Engine { IWallpaperEngineWrapper mIWallpaperEngine; + final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); + final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); + + // 2D matrix [x][y] to represent a page of a portion of a window + EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; + Bitmap mLastScreenshot; + int mLastWindowPage = -1; + private boolean mResetWindowPages; // Copies from mIWallpaperEngine. HandlerCaller mCaller; @@ -262,27 +266,11 @@ public abstract class WallpaperService extends Service { final Object mLock = new Object(); boolean mOffsetMessageEnqueued; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) float mPendingXOffset; float mPendingYOffset; float mPendingXOffsetStep; float mPendingYOffsetStep; - - /** - * local color extraction related fields - * to be used by the background thread only (except the atomic boolean) - */ - final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); - final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); - private long mLastProcessLocalColorsTimestamp; - private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); - private int mPixelCopyCount = 0; - // 2D matrix [x][y] to represent a page of a portion of a window - EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; - Bitmap mLastScreenshot; - private boolean mResetWindowPages; - boolean mPendingSync; MotionEvent mPendingMove; boolean mIsInAmbientMode; @@ -291,8 +279,12 @@ public abstract class WallpaperService extends Service { private long mLastColorInvalidation; private final Runnable mNotifyColorsChanged = this::notifyColorsChanged; + // used to throttle processLocalColors + private long mLastProcessLocalColorsTimestamp; + private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private final Supplier<Long> mClockFunction; private final Handler mHandler; + private Display mDisplay; private Context mDisplayContext; private int mDisplayState; @@ -862,7 +854,7 @@ public abstract class WallpaperService extends Service { + "was not established."); } mResetWindowPages = true; - processLocalColors(); + processLocalColors(mPendingXOffset, mPendingXOffsetStep); } catch (RemoteException e) { Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e); } @@ -1400,7 +1392,7 @@ public abstract class WallpaperService extends Service { resetWindowPages(); mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); - processLocalColors(); + processLocalColors(mPendingXOffset, mPendingXOffsetStep); } reposition(); reportEngineShown(shouldWaitForEngineShown()); @@ -1543,14 +1535,14 @@ public abstract class WallpaperService extends Service { void doVisibilityChanged(boolean visible) { if (!mDestroyed) { mVisible = visible; - reportVisibility(); - if (mReportedVisible) processLocalColors(); + reportVisibility(false); + if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); } else { AnimationHandler.requestAnimatorsEnabled(visible, this); } } - void reportVisibility() { + void reportVisibility(boolean forceReport) { if (mScreenshotSurfaceControl != null && mVisible) { if (DEBUG) Log.v(TAG, "Frozen so don't report visibility change"); return; @@ -1558,10 +1550,29 @@ public abstract class WallpaperService extends Service { if (!mDestroyed) { mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState(); boolean visible = mVisible && mDisplayState != Display.STATE_OFF; - if (mReportedVisible != visible) { + if (DEBUG) { + Log.v( + TAG, + "reportVisibility" + + " mReportedVisible=" + + mReportedVisible + + " mVisible=" + + mVisible + + " mDisplayState=" + + mDisplayState); + } + if (mReportedVisible != visible || forceReport) { mReportedVisible = visible; - if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible - + "): " + this); + if (DEBUG) { + Log.v( + TAG, + "onVisibilityChanged(" + + visible + + "): " + + this + + " forceReport=" + + forceReport); + } if (visible) { // If becoming visible, in preview mode the surface // may have been destroyed so now we need to make @@ -1628,41 +1639,31 @@ public abstract class WallpaperService extends Service { } // setup local color extraction data - processLocalColors(); + processLocalColors(xOffset, xOffsetStep); } /** * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls. */ - private void processLocalColors() { + private void processLocalColors(float xOffset, float xOffsetStep) { if (mProcessLocalColorsPending.compareAndSet(false, true)) { final long now = mClockFunction.get(); final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp; final long timeToWait = Math.max(0, PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess); - mBackgroundHandler.postDelayed(() -> { + mHandler.postDelayed(() -> { mLastProcessLocalColorsTimestamp = now + timeToWait; mProcessLocalColorsPending.set(false); - processLocalColorsInternal(); + processLocalColorsInternal(xOffset, xOffsetStep); }, timeToWait); } } - private void processLocalColorsInternal() { + private void processLocalColorsInternal(float xOffset, float xOffsetStep) { // implemented by the wallpaper if (supportsLocalColorExtraction()) return; - assertBackgroundThread(); - float xOffset; - float xOffsetStep; - float wallpaperDimAmount; - synchronized (mLock) { - xOffset = mPendingXOffset; - xOffsetStep = mPendingXOffsetStep; - wallpaperDimAmount = mWallpaperDimAmount; - } - if (DEBUG) { Log.d(TAG, "processLocalColors " + xOffset + " of step " + xOffsetStep); @@ -1725,7 +1726,7 @@ public abstract class WallpaperService extends Service { xPage = mWindowPages.length - 1; } current = mWindowPages[xPage]; - updatePage(current, xPage, xPages, wallpaperDimAmount); + updatePage(current, xPage, xPages, finalXOffsetStep); Trace.endSection(); } @@ -1745,23 +1746,16 @@ public abstract class WallpaperService extends Service { } } - /** - * Must be called with the surface lock held. - * Must not be called if the surface is not valid. - * Will unlock the surface when done using it. - */ void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages, - float wallpaperDimAmount) { - - assertBackgroundThread(); - + float xOffsetStep) { // in case the clock is zero, we start with negative time long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION; long lapsed = current - currentPage.getLastUpdateTime(); // Always update the page when the last update time is <= 0 // This is important especially when the device first boots - if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return; - + if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) { + return; + } Surface surface = mSurfaceHolder.getSurface(); if (!surface.isValid()) return; boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y; @@ -1777,42 +1771,33 @@ public abstract class WallpaperService extends Service { Bitmap screenShot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap finalScreenShot = screenShot; - final String pixelCopySectionName = "WallpaperService#pixelCopy"; - final int pixelCopyCount = mPixelCopyCount++; - Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount); - try { - PixelCopy.request(surface, screenShot, (res) -> { - Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount); - if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); - if (res != PixelCopy.SUCCESS) { - Bitmap lastBitmap = currentPage.getBitmap(); - // assign the last bitmap taken for now - currentPage.setBitmap(mLastScreenshot); - Bitmap lastScreenshot = mLastScreenshot; - if (lastScreenshot != null && !lastScreenshot.isRecycled() - && !Objects.equals(lastBitmap, lastScreenshot)) { - updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); - } - } else { - mLastScreenshot = finalScreenShot; - // going to hold this lock for a while - currentPage.setBitmap(finalScreenShot); - currentPage.setLastUpdateTime(current); - updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); + Trace.beginSection("WallpaperService#pixelCopy"); + PixelCopy.request(surface, screenShot, (res) -> { + Trace.endSection(); + if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); + if (res != PixelCopy.SUCCESS) { + Bitmap lastBitmap = currentPage.getBitmap(); + // assign the last bitmap taken for now + currentPage.setBitmap(mLastScreenshot); + Bitmap lastScreenshot = mLastScreenshot; + if (lastScreenshot != null && !lastScreenshot.isRecycled() + && !Objects.equals(lastBitmap, lastScreenshot)) { + updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); } - }, mBackgroundHandler); - } catch (IllegalArgumentException e) { - // this can potentially happen if the surface is invalidated right between the - // surface.isValid() check and the PixelCopy operation. - // in this case, stop: we'll compute colors on the next processLocalColors call. - Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy"); - } + } else { + mLastScreenshot = finalScreenShot; + // going to hold this lock for a while + currentPage.setBitmap(finalScreenShot); + currentPage.setLastUpdateTime(current); + updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); + } + }, mHandler); + } // locked by the passed page - private void updatePageColors( - EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) { + private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages, + float xOffsetStep) { if (page.getBitmap() == null) return; - assertBackgroundThread(); Trace.beginSection("WallpaperService#updatePageColors"); if (DEBUG) { Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas " @@ -1834,7 +1819,7 @@ public abstract class WallpaperService extends Service { Log.e(TAG, "Error creating page local color bitmap", e); continue; } - WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount); + WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount); target.recycle(); WallpaperColors currentColor = page.getColors(area); @@ -1851,26 +1836,17 @@ public abstract class WallpaperService extends Service { + " local color callback for area" + area + " for page " + pageIndx + " of " + numPages); } - mHandler.post(() -> { - try { - mConnection.onLocalWallpaperColorsChanged(area, color, - mDisplayContext.getDisplayId()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); - } - }); + try { + mConnection.onLocalWallpaperColorsChanged(area, color, + mDisplayContext.getDisplayId()); + } catch (RemoteException e) { + Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); + } } } Trace.endSection(); } - private void assertBackgroundThread() { - if (!mBackgroundHandler.getLooper().isCurrentThread()) { - throw new IllegalStateException( - "ProcessLocalColors should be called from the background thread"); - } - } - private RectF generateSubRect(RectF in, int pageInx, int numPages) { float minLeft = (float) (pageInx) / (float) (numPages); float maxRight = (float) (pageInx + 1) / (float) (numPages); @@ -1895,6 +1871,7 @@ public abstract class WallpaperService extends Service { if (supportsLocalColorExtraction()) return; if (!mResetWindowPages) return; mResetWindowPages = false; + mLastWindowPage = -1; for (int i = 0; i < mWindowPages.length; i++) { mWindowPages[i].setLastUpdateTime(0L); } @@ -1920,10 +1897,12 @@ public abstract class WallpaperService extends Service { if (DEBUG) { Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions); } - mBackgroundHandler.post(() -> { + mHandler.post(() -> { mLocalColorsToAdd.addAll(regions); - processLocalColors(); + processLocalColors(mPendingXOffset, mPendingYOffset); }); + + } /** @@ -1933,7 +1912,7 @@ public abstract class WallpaperService extends Service { */ public void removeLocalColorsAreas(@NonNull List<RectF> regions) { if (supportsLocalColorExtraction()) return; - mBackgroundHandler.post(() -> { + mHandler.post(() -> { float step = mPendingXOffsetStep; mLocalColorsToAdd.removeAll(regions); mLocalColorAreas.removeAll(regions); @@ -2205,22 +2184,22 @@ public abstract class WallpaperService extends Service { } } - private final DisplayListener mDisplayListener = new DisplayListener() { - @Override - public void onDisplayChanged(int displayId) { - if (mDisplay.getDisplayId() == displayId) { - reportVisibility(); - } - } + private final DisplayListener mDisplayListener = + new DisplayListener() { + @Override + public void onDisplayChanged(int displayId) { + if (mDisplay.getDisplayId() == displayId) { + boolean forceReport = mDisplay.getState() != Display.STATE_DOZE_SUSPEND; + reportVisibility(forceReport); + } + } - @Override - public void onDisplayRemoved(int displayId) { - } + @Override + public void onDisplayRemoved(int displayId) {} - @Override - public void onDisplayAdded(int displayId) { - } - }; + @Override + public void onDisplayAdded(int displayId) {} + }; private Surface getOrCreateBLASTSurface(int width, int height, int format) { Surface ret = null; @@ -2599,9 +2578,6 @@ public abstract class WallpaperService extends Service { @Override public void onCreate() { Trace.beginSection("WPMS.onCreate"); - mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor"); - mBackgroundThread.start(); - mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); super.onCreate(); Trace.endSection(); } @@ -2614,7 +2590,6 @@ public abstract class WallpaperService extends Service { engineWrapper.destroy(); } mActiveEngines.clear(); - mBackgroundThread.quitSafely(); Trace.endSection(); } diff --git a/core/java/android/text/GraphemeClusterSegmentFinder.java b/core/java/android/text/GraphemeClusterSegmentFinder.java index 656774f66792..0f6fdaf23c65 100644 --- a/core/java/android/text/GraphemeClusterSegmentFinder.java +++ b/core/java/android/text/GraphemeClusterSegmentFinder.java @@ -18,7 +18,8 @@ package android.text; import android.annotation.IntRange; import android.annotation.NonNull; -import android.graphics.Paint; +import android.graphics.TemporaryBuffer; +import android.graphics.text.GraphemeBreak; /** * Implementation of {@code SegmentFinder} using grapheme clusters as the text segment. Whitespace @@ -31,8 +32,8 @@ import android.graphics.Paint; * Segmentation - Grapheme Cluster Boundaries</a> */ public class GraphemeClusterSegmentFinder extends SegmentFinder { - private final CharSequence mText; - private final TextPaint mTextPaint; + private static AutoGrowArray.FloatArray sTempAdvances = null; + private final boolean[] mIsGraphemeBreak; /** * Constructs a GraphemeClusterSegmentFinder instance for the specified text which uses the @@ -43,51 +44,73 @@ public class GraphemeClusterSegmentFinder extends SegmentFinder { */ public GraphemeClusterSegmentFinder( @NonNull CharSequence text, @NonNull TextPaint textPaint) { - mText = text; - mTextPaint = textPaint; + + if (sTempAdvances == null) { + sTempAdvances = new AutoGrowArray.FloatArray(text.length()); + } else if (sTempAdvances.size() < text.length()) { + sTempAdvances.resize(text.length()); + } + + mIsGraphemeBreak = new boolean[text.length()]; + float[] advances = sTempAdvances.getRawArray(); + char[] chars = TemporaryBuffer.obtain(text.length()); + + TextUtils.getChars(text, 0, text.length(), chars, 0); + + textPaint.getTextWidths(chars, 0, text.length(), advances); + + GraphemeBreak.isGraphemeBreak(advances, chars, /* start= */ 0, /* end= */ text.length(), + mIsGraphemeBreak); + TemporaryBuffer.recycle(chars); + } + + private int previousBoundary(@IntRange(from = 0) int offset) { + if (offset <= 0) return DONE; + do { + --offset; + } while (offset > 0 && !mIsGraphemeBreak[offset]); + return offset; + } + + private int nextBoundary(@IntRange(from = 0) int offset) { + if (offset >= mIsGraphemeBreak.length) return DONE; + do { + ++offset; + } while (offset < mIsGraphemeBreak.length && !mIsGraphemeBreak[offset]); + return offset; } @Override public int previousStartBoundary(@IntRange(from = 0) int offset) { - if (offset == 0) return DONE; - int boundary = mTextPaint.getTextRunCursor( - mText, 0, mText.length(), false, offset, Paint.CURSOR_BEFORE); - return boundary == -1 ? DONE : boundary; + return previousBoundary(offset); } @Override public int previousEndBoundary(@IntRange(from = 0) int offset) { if (offset == 0) return DONE; - int boundary = mTextPaint.getTextRunCursor( - mText, 0, mText.length(), false, offset, Paint.CURSOR_BEFORE); + int boundary = previousBoundary(offset); // Check that there is another cursor position before, otherwise this is not a valid // end boundary. - if (mTextPaint.getTextRunCursor( - mText, 0, mText.length(), false, boundary, Paint.CURSOR_BEFORE) == -1) { + if (boundary == DONE || previousBoundary(boundary) == DONE) { return DONE; } - return boundary == -1 ? DONE : boundary; + return boundary; } @Override public int nextStartBoundary(@IntRange(from = 0) int offset) { - if (offset == mText.length()) return DONE; - int boundary = mTextPaint.getTextRunCursor( - mText, 0, mText.length(), false, offset, Paint.CURSOR_AFTER); + if (offset == mIsGraphemeBreak.length) return DONE; + int boundary = nextBoundary(offset); // Check that there is another cursor position after, otherwise this is not a valid // start boundary. - if (mTextPaint.getTextRunCursor( - mText, 0, mText.length(), false, boundary, Paint.CURSOR_AFTER) == -1) { + if (boundary == DONE || nextBoundary(boundary) == DONE) { return DONE; } - return boundary == -1 ? DONE : boundary; + return boundary; } @Override public int nextEndBoundary(@IntRange(from = 0) int offset) { - if (offset == mText.length()) return DONE; - int boundary = mTextPaint.getTextRunCursor( - mText, 0, mText.length(), false, offset, Paint.CURSOR_AFTER); - return boundary == -1 ? DONE : boundary; + return nextBoundary(offset); } } diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index a746dc6c15f0..6201b3a91eff 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -164,10 +164,10 @@ public class FeatureFlagUtils { */ public static final String SETTINGS_AUDIO_ROUTING = "settings_audio_routing"; - /** Flag to enable/disable flash alerts + /** Flag to enable/disable flash notifications * @hide */ - public static final String SETTINGS_FLASH_ALERTS = "settings_flash_alerts"; + public static final String SETTINGS_FLASH_NOTIFICATIONS = "settings_flash_notifications"; /** * Flag to disable/enable showing udfps enroll view in settings. If it's disabled, udfps enroll @@ -220,9 +220,9 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true"); DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true"); DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false"); - DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false"); - DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "false"); - DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false"); + DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "true"); + DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "true"); + DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "true"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_PHASE2, "false"); @@ -232,7 +232,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, "false"); DEFAULT_FLAGS.put(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM, "false"); DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false"); - DEFAULT_FLAGS.put(SETTINGS_FLASH_ALERTS, "false"); + DEFAULT_FLAGS.put(SETTINGS_FLASH_NOTIFICATIONS, "true"); DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "false"); DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "false"); diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 3cf56c0668c8..6804c5ca3e4f 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -172,7 +172,7 @@ public final class AccessibilityInteractionController { private boolean isVisibleToAccessibilityService(View view) { return view != null && (mA11yManager.isRequestFromAccessibilityTool() - || !view.isAccessibilityDataPrivate()); + || !view.isAccessibilityDataSensitive()); } public void findAccessibilityNodeInfoByAccessibilityIdClientThread( diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 4a83bbe7e72b..8c4e90c81147 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -197,6 +197,7 @@ public final class Choreographer { private int mFPSDivisor = 1; private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = new DisplayEventReceiver.VsyncEventData(); + private final FrameData mFrameData = new FrameData(); /** * Contains information about the current frame for jank-tracking, @@ -789,7 +790,7 @@ public final class Choreographer { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId); } - FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData); + mFrameData.update(frameTimeNanos, vsyncEventData); synchronized (mLock) { if (!mFrameScheduled) { traceMessage("Frame not scheduled"); @@ -827,7 +828,7 @@ public final class Choreographer { + " ms in the past."); } } - frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); + mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); } if (frameTimeNanos < mLastFrameTimeNanos) { @@ -862,17 +863,16 @@ public final class Choreographer { AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); - doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos); + doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos); mFrameInfo.markAnimationsStart(); - doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos); - doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData, - frameIntervalNanos); + doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos); + doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos); mFrameInfo.markPerformTraversalsStart(); - doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos); + doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos); - doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos); + doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); @@ -886,9 +886,9 @@ public final class Choreographer { } } - void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) { + void doCallbacks(int callbackType, long frameIntervalNanos) { CallbackRecord callbacks; - long frameTimeNanos = frameData.mFrameTimeNanos; + long frameTimeNanos = mFrameData.mFrameTimeNanos; synchronized (mLock) { // We use "now" to determine when callbacks become due because it's possible // for earlier processing phases in a frame to post callbacks that should run @@ -925,7 +925,7 @@ public final class Choreographer { } frameTimeNanos = now - lastFrameOffset; mLastFrameTimeNanos = frameTimeNanos; - frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos); + mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); } } } @@ -937,7 +937,7 @@ public final class Choreographer { + ", action=" + c.action + ", token=" + c.token + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); } - c.run(frameData); + c.run(mFrameData); } } finally { synchronized (mLock) { @@ -1039,21 +1039,38 @@ public final class Choreographer { /** Holds data that describes one possible VSync frame event to render at. */ public static class FrameTimeline { - FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) { - this.mVsyncId = vsyncId; - this.mExpectedPresentTimeNanos = expectedPresentTimeNanos; - this.mDeadlineNanos = deadlineNanos; + private long mVsyncId = FrameInfo.INVALID_VSYNC_ID; + private long mExpectedPresentationTimeNanos = -1; + private long mDeadlineNanos = -1; + private boolean mInCallback = false; + + FrameTimeline() { + // Intentionally empty; defined so that it is not API/public by default. + } + + void setInCallback(boolean inCallback) { + mInCallback = inCallback; } - private long mVsyncId; - private long mExpectedPresentTimeNanos; - private long mDeadlineNanos; + private void checkInCallback() { + if (!mInCallback) { + throw new IllegalStateException( + "FrameTimeline is not valid outside of the vsync callback"); + } + } + + void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) { + mVsyncId = vsyncId; + mExpectedPresentationTimeNanos = expectedPresentationTimeNanos; + mDeadlineNanos = deadlineNanos; + } /** * The id that corresponds to this frame timeline, used to correlate a frame * produced by HWUI with the timeline data stored in Surface Flinger. */ public long getVsyncId() { + checkInCallback(); return mVsyncId; } @@ -1062,13 +1079,15 @@ public final class Choreographer { * presented. */ public long getExpectedPresentationTimeNanos() { - return mExpectedPresentTimeNanos; + checkInCallback(); + return mExpectedPresentationTimeNanos; } /** * The time in {@link System#nanoTime()} timebase which this frame needs to be ready by. */ public long getDeadlineNanos() { + checkInCallback(); return mDeadlineNanos; } } @@ -1079,24 +1098,21 @@ public final class Choreographer { * information including deadline and expected present time. */ public static class FrameData { - FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { - this.mFrameTimeNanos = frameTimeNanos; - this.mFrameTimelines = convertFrameTimelines(vsyncEventData); - this.mPreferredFrameTimelineIndex = - vsyncEventData.preferredFrameTimelineIndex; - } - private long mFrameTimeNanos; - private final FrameTimeline[] mFrameTimelines; + private final FrameTimeline[] mFrameTimelines = + new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH]; private int mPreferredFrameTimelineIndex; + private boolean mInCallback = false; - void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) { - mFrameTimeNanos = frameTimeNanos; - mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; + FrameData() { + for (int i = 0; i < mFrameTimelines.length; i++) { + mFrameTimelines[i] = new FrameTimeline(); + } } /** The time in nanoseconds when the frame started being rendered. */ public long getFrameTimeNanos() { + checkInCallback(); return mFrameTimeNanos; } @@ -1104,58 +1120,83 @@ public final class Choreographer { @NonNull @SuppressLint("ArrayReturn") // For API consistency and speed. public FrameTimeline[] getFrameTimelines() { + checkInCallback(); return mFrameTimelines; } /** The platform-preferred frame timeline. */ @NonNull public FrameTimeline getPreferredFrameTimeline() { + checkInCallback(); return mFrameTimelines[mPreferredFrameTimelineIndex]; } - private FrameTimeline[] convertFrameTimelines( - DisplayEventReceiver.VsyncEventData vsyncEventData) { - FrameTimeline[] frameTimelines = - new FrameTimeline[vsyncEventData.frameTimelines.length]; + void setInCallback(boolean inCallback) { + mInCallback = inCallback; + for (int i = 0; i < mFrameTimelines.length; i++) { + mFrameTimelines[i].setInCallback(inCallback); + } + } + + private void checkInCallback() { + if (!mInCallback) { + throw new IllegalStateException( + "FrameData is not valid outside of the vsync callback"); + } + } + + /** + * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from + * native. + */ + void update(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { + if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) { + throw new IllegalStateException( + "Length of native frame timelines received does not match Java. Did " + + "FRAME_TIMELINES_LENGTH or kFrameTimelinesLength (native) " + + "change?"); + } + mFrameTimeNanos = frameTimeNanos; + mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex; for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) { DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i]; - frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId, - frameTimeline.expectedPresentTime, frameTimeline.deadline); + mFrameTimelines[i].update(frameTimeline.vsyncId, + frameTimeline.expectedPresentationTime, frameTimeline.deadline); } - return frameTimelines; } - } - /** - * Update the frame data when the frame is late. - * - * @param jitterNanos currentTime - frameTime - */ - private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData, - long jitterNanos) { - int newPreferredIndex = 0; - FrameTimeline[] frameTimelines = frameData.getFrameTimelines(); - final long minimumDeadline = - frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos; - // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder - // query for new frame data. Note that binder is relatively slow, O(ms), so it is - // only called when the existing frame data does not hold a valid frame. - while (newPreferredIndex < frameTimelines.length - 1 - && frameTimelines[newPreferredIndex].getDeadlineNanos() - < minimumDeadline) { - newPreferredIndex++; + /** + * Update the frame data when the frame is late. + * + * @param jitterNanos currentTime - frameTime + */ + void update( + long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) { + int newPreferredIndex = 0; + final long minimumDeadline = + mFrameTimelines[mPreferredFrameTimelineIndex].mDeadlineNanos + jitterNanos; + // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder + // query for new frame data. Note that binder is relatively slow, O(ms), so it is + // only called when the existing frame data does not hold a valid frame. + while (newPreferredIndex < mFrameTimelines.length - 1 + && mFrameTimelines[newPreferredIndex].mDeadlineNanos < minimumDeadline) { + newPreferredIndex++; + } + + long newPreferredDeadline = mFrameTimelines[newPreferredIndex].mDeadlineNanos; + if (newPreferredDeadline < minimumDeadline) { + DisplayEventReceiver.VsyncEventData latestVsyncEventData = + displayEventReceiver.getLatestVsyncEventData(); + update(frameTimeNanos, latestVsyncEventData); + } else { + update(frameTimeNanos, newPreferredIndex); + } } - long newPreferredDeadline = - frameData.getFrameTimelines()[newPreferredIndex].getDeadlineNanos(); - if (newPreferredDeadline < minimumDeadline) { - DisplayEventReceiver.VsyncEventData latestVsyncEventData = - mDisplayEventReceiver.getLatestVsyncEventData(); - return new FrameData(frameTimeNanos, latestVsyncEventData); - } else { - frameData.updateFrameData(frameTimeNanos, newPreferredIndex); - return frameData; + void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) { + mFrameTimeNanos = frameTimeNanos; + mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex; } } @@ -1280,11 +1321,13 @@ public final class Choreographer { } void run(FrameData frameData) { + frameData.setInCallback(true); if (token == VSYNC_CALLBACK_TOKEN) { ((VsyncCallback) action).onVsync(frameData); } else { run(frameData.getFrameTimeNanos()); } + frameData.setInCallback(false); } } diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index edce00181335..b4675e0127de 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -81,7 +81,10 @@ public abstract class DisplayEventReceiver { // GC'd while the native peer of the receiver is using them. private MessageQueue mMessageQueue; + private final VsyncEventData mVsyncEventData = new VsyncEventData(); + private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, + WeakReference<VsyncEventData> vsyncEventData, MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle); private static native long nativeGetDisplayEventReceiverFinalizer(); @FastNative @@ -124,7 +127,9 @@ public abstract class DisplayEventReceiver { } mMessageQueue = looper.getQueue(); - mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, + mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), + new WeakReference<VsyncEventData>(mVsyncEventData), + mMessageQueue, vsyncSource, eventRegistration, layerHandle); mFreeNativeResources = sNativeAllocationRegistry.registerNativeAllocation(this, mReceiverPtr); @@ -142,27 +147,33 @@ public abstract class DisplayEventReceiver { } static final class VsyncEventData { - - static final FrameTimeline[] INVALID_FRAME_TIMELINES = - {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)}; + // The amount of frame timeline choices. + // Must be in sync with VsyncEventData::kFrameTimelinesLength in + // frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime + // assertion is thrown when Choreographer is processing VsyncEventData. + static final int FRAME_TIMELINES_LENGTH = 7; public static class FrameTimeline { - FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) { + FrameTimeline() {} + + // Called from native code. + @SuppressWarnings("unused") + FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) { this.vsyncId = vsyncId; - this.expectedPresentTime = expectedPresentTime; + this.expectedPresentationTime = expectedPresentationTime; this.deadline = deadline; } // The frame timeline vsync id, used to correlate a frame // produced by HWUI with the timeline data stored in Surface Flinger. - public final long vsyncId; + public long vsyncId = FrameInfo.INVALID_VSYNC_ID; // The frame timestamp for when the frame is expected to be presented. - public final long expectedPresentTime; + public long expectedPresentationTime = Long.MAX_VALUE; // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is // allotted for the frame to be completed. - public final long deadline; + public long deadline = Long.MAX_VALUE; } /** @@ -170,11 +181,18 @@ public abstract class DisplayEventReceiver { * {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily * delayed by the app. */ - public final long frameInterval; + public long frameInterval = -1; public final FrameTimeline[] frameTimelines; - public final int preferredFrameTimelineIndex; + public int preferredFrameTimelineIndex = 0; + + VsyncEventData() { + frameTimelines = new FrameTimeline[FRAME_TIMELINES_LENGTH]; + for (int i = 0; i < frameTimelines.length; i++) { + frameTimelines[i] = new FrameTimeline(); + } + } // Called from native code. @SuppressWarnings("unused") @@ -185,12 +203,6 @@ public abstract class DisplayEventReceiver { this.frameInterval = frameInterval; } - VsyncEventData() { - this.frameInterval = -1; - this.frameTimelines = INVALID_FRAME_TIMELINES; - this.preferredFrameTimelineIndex = 0; - } - public FrameTimeline preferredFrameTimeline() { return frameTimelines[preferredFrameTimelineIndex]; } @@ -294,9 +306,8 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") - private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, - VsyncEventData vsyncEventData) { - onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData); + private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) { + onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData); } // Called from native code. diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 03689188a9b3..e31adcfd699e 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -24,6 +24,7 @@ import static android.view.DisplayInfoProto.LOGICAL_HEIGHT; import static android.view.DisplayInfoProto.LOGICAL_WIDTH; import static android.view.DisplayInfoProto.NAME; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; @@ -37,6 +38,7 @@ import android.os.Parcelable; import android.os.Process; import android.util.ArraySet; import android.util.DisplayMetrics; +import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.display.BrightnessSynchronizer; @@ -348,6 +350,12 @@ public final class DisplayInfo implements Parcelable { */ public float hdrSdrRatio = Float.NaN; + /** + * RefreshRateRange limitation for @Temperature.ThrottlingStatus + */ + @NonNull + public SparseArray<SurfaceControl.RefreshRateRange> refreshRateThermalThrottling = + new SparseArray<>(); public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() { @Override @@ -425,7 +433,8 @@ public final class DisplayInfo implements Parcelable { && installOrientation == other.installOrientation && Objects.equals(displayShape, other.displayShape) && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate) - && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio); + && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio) + && refreshRateThermalThrottling.contentEquals(other.refreshRateThermalThrottling); } @Override @@ -482,6 +491,7 @@ public final class DisplayInfo implements Parcelable { displayShape = other.displayShape; layoutLimitedRefreshRate = other.layoutLimitedRefreshRate; hdrSdrRatio = other.hdrSdrRatio; + refreshRateThermalThrottling = other.refreshRateThermalThrottling; } public void readFromParcel(Parcel source) { @@ -544,6 +554,8 @@ public final class DisplayInfo implements Parcelable { displayShape = source.readTypedObject(DisplayShape.CREATOR); layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR); hdrSdrRatio = source.readFloat(); + refreshRateThermalThrottling = source.readSparseArray(null, + SurfaceControl.RefreshRateRange.class); } @Override @@ -604,6 +616,7 @@ public final class DisplayInfo implements Parcelable { dest.writeTypedObject(displayShape, flags); dest.writeTypedObject(layoutLimitedRefreshRate, flags); dest.writeFloat(hdrSdrRatio); + dest.writeSparseArray(refreshRateThermalThrottling); } @Override @@ -871,6 +884,8 @@ public final class DisplayInfo implements Parcelable { } else { sb.append(hdrSdrRatio); } + sb.append(", refreshRateThermalThrottling "); + sb.append(refreshRateThermalThrottling); sb.append("}"); return sb.toString(); } diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index 98f61a366381..fa926129b823 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -172,9 +172,13 @@ public class HandwritingInitiator { if (candidateView == getConnectedView()) { startHandwriting(candidateView); } else if (candidateView.getHandwritingDelegatorCallback() != null) { + String delegatePackageName = + candidateView.getAllowedHandwritingDelegatePackageName(); + if (delegatePackageName == null) { + delegatePackageName = candidateView.getContext().getOpPackageName(); + } mImm.prepareStylusHandwritingDelegation( - candidateView, - candidateView.getAllowedHandwritingDelegatePackageName()); + candidateView, delegatePackageName); candidateView.getHandwritingDelegatorCallback().run(); } else { if (candidateView.getRevealOnFocusHint()) { @@ -299,8 +303,12 @@ public class HandwritingInitiator { */ @VisibleForTesting public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) { - if (mImm.acceptStylusHandwritingDelegation( - view, view.getAllowedHandwritingDelegatorPackageName())) { + String delegatorPackageName = + view.getAllowedHandwritingDelegatorPackageName(); + if (delegatorPackageName == null) { + delegatorPackageName = view.getContext().getOpPackageName(); + } + if (mImm.acceptStylusHandwritingDelegation(view, delegatorPackageName)) { if (mState != null) { mState.mHasInitiatedHandwriting = true; mState.mShouldInitHandwriting = false; diff --git a/core/java/android/view/MotionPredictor.java b/core/java/android/view/MotionPredictor.java index 4d32efea9081..7d452f954fb0 100644 --- a/core/java/android/view/MotionPredictor.java +++ b/core/java/android/view/MotionPredictor.java @@ -17,14 +17,11 @@ package android.view; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import libcore.util.NativeAllocationRegistry; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - /** * Calculate motion predictions. * @@ -68,9 +65,12 @@ public final class MotionPredictor { /** * Record a movement so that in the future, a prediction for the current gesture can be - * generated. Ensure to add all motions from the gesture of interest to generate correct - * predictions. + * generated. Only gestures from one input device at a time should be provided to an instance of + * MotionPredictor. + * * @param event The received event + * + * @throws IllegalArgumentException if an inconsistent MotionEvent stream is sent. */ public void record(@NonNull MotionEvent event) { if (!isPredictionEnabled()) { @@ -80,28 +80,24 @@ public final class MotionPredictor { } /** - * Get predicted events for all gestures that have been provided to {@link #record}. - * If events from multiple devices were sent to 'record', this will produce a separate - * {@link MotionEvent} for each device. The returned list may be empty if no predictions for - * any of the added events/devices are available. + * Get a predicted event for the gesture that has been provided to {@link #record}. * Predictions may not reach the requested timestamp if the confidence in the prediction results * is low. * * @param predictionTimeNanos The time that the prediction should target, in the * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds. * - * @return A list of predicted motion events, with at most one for each device observed by - * {@link #record}. Be sure to check the historical data in addition to the latest - * ({@link MotionEvent#getX getX()}, {@link MotionEvent#getY getY()}) coordinates for smooth - * prediction curves. An empty list is returned if predictions are not supported, or not - * possible for the current set of gestures. + * @return The predicted motion event, or `null` if predictions are not supported, or not + * possible for the current gesture. Be sure to check the historical data in addition to the + * latest ({@link MotionEvent#getX getX()}, {@link MotionEvent#getY getY()}) coordinates for + * smooth prediction curves. */ - @NonNull - public List<MotionEvent> predict(long predictionTimeNanos) { + @Nullable + public MotionEvent predict(long predictionTimeNanos) { if (!isPredictionEnabled()) { - return Collections.emptyList(); + return null; } - return Arrays.asList(nativePredict(mPtr, predictionTimeNanos)); + return nativePredict(mPtr, predictionTimeNanos); } private boolean isPredictionEnabled() { @@ -129,7 +125,7 @@ public final class MotionPredictor { private static native long nativeInitialize(int offsetNanos); private static native void nativeRecord(long nativePtr, MotionEvent event); - private static native MotionEvent[] nativePredict(long nativePtr, long predictionTimeNanos); + private static native MotionEvent nativePredict(long nativePtr, long predictionTimeNanos); private static native boolean nativeIsPredictionAvailable(long nativePtr, int deviceId, int source); private static native long nativeGetNativeMotionPredictorFinalizer(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index fee20517a499..8bf32324dd5a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3114,33 +3114,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Accessibility interactions from services without {@code isAccessibilityTool} set to true are * disallowed for any of the following conditions: * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li> - * <li>any parent of this view returns true from {@link #isAccessibilityDataPrivate()}.</li> + * <li>any parent of this view returns true from {@link #isAccessibilityDataSensitive()}.</li> * </p> */ - public static final int ACCESSIBILITY_DATA_PRIVATE_AUTO = 0x00000000; + public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000; /** * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} * property set to true. */ - public static final int ACCESSIBILITY_DATA_PRIVATE_YES = 0x00000001; + public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001; /** * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s, * regardless of their * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property. */ - public static final int ACCESSIBILITY_DATA_PRIVATE_NO = 0x00000002; + public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002; /** @hide */ - @IntDef(prefix = { "ACCESSIBILITY_DATA_PRIVATE_" }, value = { - ACCESSIBILITY_DATA_PRIVATE_AUTO, - ACCESSIBILITY_DATA_PRIVATE_YES, - ACCESSIBILITY_DATA_PRIVATE_NO, + @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = { + ACCESSIBILITY_DATA_SENSITIVE_AUTO, + ACCESSIBILITY_DATA_SENSITIVE_YES, + ACCESSIBILITY_DATA_SENSITIVE_NO, }) @Retention(RetentionPolicy.SOURCE) - public @interface AccessibilityDataPrivate {} + public @interface AccessibilityDataSensitive {} /** * Mask for obtaining the bits which specify how to determine @@ -4611,9 +4611,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property * set to true. */ - private int mExplicitAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_AUTO; - /** Used to calculate and cache {@link #isAccessibilityDataPrivate()}. */ - private int mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_AUTO; + private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; + /** Used to calculate and cache {@link #isAccessibilityDataSensitive()}. */ + private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; /** * Specifies the id of a view for which this view serves as a label for @@ -6016,9 +6016,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAccessibility(a.getInt(attr, IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); break; - case R.styleable.View_accessibilityDataPrivate: - setAccessibilityDataPrivate(a.getInt(attr, - ACCESSIBILITY_DATA_PRIVATE_AUTO)); + case R.styleable.View_accessibilityDataSensitive: + setAccessibilityDataSensitive(a.getInt(attr, + ACCESSIBILITY_DATA_SENSITIVE_AUTO)); break; case R.styleable.View_accessibilityLiveRegion: setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); @@ -8660,9 +8660,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * is responsible for handling this call. * </p> * <p> - * If this view sets {@link #isAccessibilityDataPrivate()} then this view should only append + * If this view sets {@link #isAccessibilityDataSensitive()} then this view should only append * sensitive information to an event that also sets - * {@link AccessibilityEvent#isAccessibilityDataPrivate()}. + * {@link AccessibilityEvent#isAccessibilityDataSensitive()}. * </p> * <p> * <em>Note:</em> Accessibility events of certain types are not dispatched for @@ -8920,7 +8920,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ @UnsupportedAppUsage - public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { + @TestApi + public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { if (mAttachInfo == null) { return; } @@ -8928,6 +8929,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, getBoundsToScreenInternal(position, clipToParent); outRect.set(Math.round(position.left), Math.round(position.top), Math.round(position.right), Math.round(position.bottom)); + // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded + // will sandbox outRect within window bounds. + mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); } /** @@ -10697,6 +10701,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.setVisibleToUser(isVisibleToUser()); info.setImportantForAccessibility(isImportantForAccessibility()); + info.setAccessibilityDataSensitive(isAccessibilityDataSensitive()); info.setPackageName(mContext.getPackageName()); info.setClassName(getAccessibilityClassName()); info.setStateDescription(getStateDescription()); @@ -12437,11 +12442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { mHandwritingDelegatorCallback = callback; if (callback != null) { - // By default, the delegate must be from the same package as the delegator view. - mAllowedHandwritingDelegatePackageName = mContext.getOpPackageName(); setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); - } else { - mAllowedHandwritingDelegatePackageName = null; } } @@ -12460,8 +12461,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * view from the specified package. If this method is not called, delegators may only be used to * initiate handwriting mode for a delegate editor view from the same package as the delegator * view. This method allows specifying a different trusted package which may contain a delegate - * editor view linked to this delegator view. This should be called after {@link - * #setHandwritingDelegatorCallback}. + * editor view linked to this delegator view. + * + * <p>This method has no effect unless {@link #setHandwritingDelegatorCallback} is also called + * to configure this view to act as a handwriting delegator. * * <p>If this method is called on the delegator view, then {@link * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view. @@ -12479,33 +12482,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);</pre> * * @param allowedPackageName the package name of a delegate editor view linked to this delegator - * view - * @throws IllegalStateException If the view has not been configured as a handwriting delegator - * using {@link #setHandwritingDelegatorCallback}. + * view, or {@code null} to restore the default behavior of only allowing delegate editor + * views from the same package as this delegator view */ - public void setAllowedHandwritingDelegatePackage(@NonNull String allowedPackageName) { - if (mHandwritingDelegatorCallback == null) { - throw new IllegalStateException("This view is not a handwriting delegator."); - } + public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) { mAllowedHandwritingDelegatePackageName = allowedPackageName; } /** * Returns the allowed package for delegate editor views for which this view may act as a - * handwriting delegator. If {@link #setAllowedHandwritingDelegatePackage} has not been called, - * this will return this view's package name, since by default delegators may only be used to - * initiate handwriting mode for a delegate editor view from the same package as the delegator - * view. This will return a different allowed package if set by {@link - * #setAllowedHandwritingDelegatePackage}. - * - * @throws IllegalStateException If the view has not been configured as a handwriting delegator - * using {@link #setHandwritingDelegatorCallback}. + * handwriting delegator, as set by {@link #setAllowedHandwritingDelegatePackage}. If {@link + * #setAllowedHandwritingDelegatePackage} has not been called, or called with {@code null} + * argument, this will return {@code null}, meaning that this delegator view may only be used to + * initiate handwriting mode for a delegate editor view from the same package as this delegator + * view. */ - @NonNull + @Nullable public String getAllowedHandwritingDelegatePackageName() { - if (mHandwritingDelegatorCallback == null) { - throw new IllegalStateException("This view is not a handwriting delegator."); - } return mAllowedHandwritingDelegatePackageName; } @@ -12519,12 +12512,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { mIsHandwritingDelegate = isHandwritingDelegate; - if (mIsHandwritingDelegate) { - // By default, the delegator must be from the same package as the delegate view. - mAllowedHandwritingDelegatorPackageName = mContext.getOpPackageName(); - } else { - mAllowedHandwritingDelegatePackageName = null; - } } /** @@ -12537,41 +12524,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Specifies that a view from the specified package may act as a handwriting delegator for this - * delegate editor view. If this method is not called, only views from the same package as the + * delegate editor view. If this method is not called, only views from the same package as this * delegate editor view may act as a handwriting delegator. This method allows specifying a * different trusted package which may contain a delegator view linked to this delegate editor - * view. This should be called after {@link #setIsHandwritingDelegate}. + * view. + * + * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to + * configure this view to act as a handwriting delegate. * * <p>If this method is called on the delegate editor view, then {@link * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view. * * @param allowedPackageName the package name of a delegator view linked to this delegate editor - * view - * @throws IllegalStateException If the view has not been configured as a handwriting delegate - * using {@link #setIsHandwritingDelegate}. + * view, or {@code null} to restore the default behavior of only allowing delegator views + * from the same package as this delegate editor view */ - public void setAllowedHandwritingDelegatorPackage(@NonNull String allowedPackageName) { - if (!mIsHandwritingDelegate) { - throw new IllegalStateException("This view is not a handwriting delegate."); - } + public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) { mAllowedHandwritingDelegatorPackageName = allowedPackageName; } /** * Returns the allowed package for views which may act as a handwriting delegator for this - * delegate editor view. If {@link #setAllowedHandwritingDelegatorPackage} has not been called, - * this will return this view's package name, since by default only views from the same package - * as the delegator editor view may act as a handwriting delegator. This will return a different - * allowed package if set by {@link #setAllowedHandwritingDelegatorPackage}. - * - * @throws IllegalStateException If the view has not been configured as a handwriting delegate - * using {@link #setIsHandwritingDelegate}. + * delegate editor view, as set by {@link #setAllowedHandwritingDelegatorPackage}. If {@link + * #setAllowedHandwritingDelegatorPackage} has not been called, or called with {@code null} + * argument, this will return {@code null}, meaning that only views from the same package as + * this delegator editor view may act as a handwriting delegator. */ - @NonNull + @Nullable public String getAllowedHandwritingDelegatorPackageName() { - if (!mIsHandwritingDelegate) { - throw new IllegalStateException("This view is not a handwriting delegate."); - } return mAllowedHandwritingDelegatorPackageName; } @@ -13606,7 +13586,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void setFilterTouchesWhenObscured(boolean enabled) { setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, FILTER_TOUCHES_WHEN_OBSCURED); - calculateAccessibilityDataPrivate(); + calculateAccessibilityDataSensitive(); } /** @@ -14842,7 +14822,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // source View's AccessibilityDataPrivate value, and then filtering is done when // AccessibilityManagerService propagates events to each recipient AccessibilityService. if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool() - && isAccessibilityDataPrivate()) { + && isAccessibilityDataSensitive()) { return false; } } @@ -14858,43 +14838,43 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * set to true. * * <p> - * See default behavior provided by {@link #ACCESSIBILITY_DATA_PRIVATE_AUTO}. Otherwise, - * returns true for {@link #ACCESSIBILITY_DATA_PRIVATE_YES} or false for {@link - * #ACCESSIBILITY_DATA_PRIVATE_NO}. + * See default behavior provided by {@link #ACCESSIBILITY_DATA_SENSITIVE_AUTO}. Otherwise, + * returns true for {@link #ACCESSIBILITY_DATA_SENSITIVE_YES} or false for {@link + * #ACCESSIBILITY_DATA_SENSITIVE_NO}. * </p> * * @return True if this view should restrict accessibility service access to services that have * the isAccessibilityTool property. */ @ViewDebug.ExportedProperty(category = "accessibility") - public boolean isAccessibilityDataPrivate() { - if (mInferredAccessibilityDataPrivate == ACCESSIBILITY_DATA_PRIVATE_AUTO) { - calculateAccessibilityDataPrivate(); + public boolean isAccessibilityDataSensitive() { + if (mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_AUTO) { + calculateAccessibilityDataSensitive(); } - return mInferredAccessibilityDataPrivate == ACCESSIBILITY_DATA_PRIVATE_YES; + return mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_YES; } /** - * Calculate and cache the inferred value for {@link #isAccessibilityDataPrivate()}. + * Calculate and cache the inferred value for {@link #isAccessibilityDataSensitive()}. * * <p> * <strong>Note:</strong> This method needs to be called any time one of the below conditions * changes, to recalculate the new value. * </p> */ - void calculateAccessibilityDataPrivate() { + void calculateAccessibilityDataSensitive() { // Use the explicit value if set. - if (mExplicitAccessibilityDataPrivate != ACCESSIBILITY_DATA_PRIVATE_AUTO) { - mInferredAccessibilityDataPrivate = mExplicitAccessibilityDataPrivate; + if (mExplicitAccessibilityDataSensitive != ACCESSIBILITY_DATA_SENSITIVE_AUTO) { + mInferredAccessibilityDataSensitive = mExplicitAccessibilityDataSensitive; } else if (getFilterTouchesWhenObscured()) { - // Views that set filterTouchesWhenObscured default to accessibilityDataPrivate. - mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES; - } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataPrivate()) { - // Descendants of an accessibilityDataPrivate View are also accessibilityDataPrivate. - mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES; + // Views that set filterTouchesWhenObscured default to accessibilityDataSensitive. + mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; + } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataSensitive()) { + // Descendants of accessibilityDataSensitive Views are also accessibilityDataSensitive. + mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; } else { - // Otherwise, default to not accessibilityDataPrivate. - mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_NO; + // Otherwise, default to not accessibilityDataSensitive. + mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_NO; } } @@ -14904,10 +14884,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property * set to true. */ - public void setAccessibilityDataPrivate( - @AccessibilityDataPrivate int accessibilityDataPrivate) { - mExplicitAccessibilityDataPrivate = accessibilityDataPrivate; - calculateAccessibilityDataPrivate(); + public void setAccessibilityDataSensitive( + @AccessibilityDataSensitive int accessibilityDataSensitive) { + mExplicitAccessibilityDataSensitive = accessibilityDataSensitive; + calculateAccessibilityDataSensitive(); } /** @@ -16183,7 +16163,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ @UnsupportedAppUsage - public void getWindowDisplayFrame(Rect outRect) { + @TestApi + public void getWindowDisplayFrame(@NonNull Rect outRect) { if (mAttachInfo != null) { mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); return; @@ -26399,6 +26380,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (info != null) { outLocation[0] += info.mWindowLeft; outLocation[1] += info.mWindowTop; + // If OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS override is enabled, + // applyViewLocationSandboxingIfNeeded sandboxes outLocation within window bounds. + info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation); } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 73d447141cc1..46ae3ea21890 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3921,10 +3921,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } @Override - void calculateAccessibilityDataPrivate() { - super.calculateAccessibilityDataPrivate(); + void calculateAccessibilityDataSensitive() { + super.calculateAccessibilityDataSensitive(); for (int i = 0; i < mChildrenCount; i++) { - mChildren[i].calculateAccessibilityDataPrivate(); + mChildren[i].calculateAccessibilityDataSensitive(); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 71a3a7b7cc51..a8b4da14c1c5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; @@ -79,6 +80,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; +import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS; import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW; import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; @@ -92,12 +94,14 @@ import android.animation.LayoutTransition; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Size; import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ICompatCameraControlCallback; import android.app.ResourcesManager; import android.app.WindowConfiguration; +import android.app.compat.CompatChanges; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; @@ -895,6 +899,15 @@ public final class ViewRootImpl implements ViewParent, private boolean mRelayoutRequested; + /** + * Whether sandboxing of {@link android.view.View#getBoundsOnScreen}, + * {@link android.view.View#getLocationOnScreen(int[])}, + * {@link android.view.View#getWindowDisplayFrame} and + * {@link android.view.View#getWindowVisibleDisplayFrame} + * within Activity bounds is enabled for the current application. + */ + private final boolean mViewBoundsSandboxingEnabled; + private int mLastTransformHint = Integer.MIN_VALUE; private AccessibilityWindowAttributes mAccessibilityWindowAttributes; @@ -986,6 +999,8 @@ public final class ViewRootImpl implements ViewParent, mViewConfiguration, mContext.getSystemService(InputMethodManager.class)); + mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled(); + String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); if (processorOverrideName.isEmpty()) { @@ -1650,6 +1665,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mThreadedRenderer = renderer; renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); updateColorModeIfNeeded(attrs.getColorMode()); + updateRenderHdrSdrRatio(); updateForceDarkMode(); mAttachInfo.mHardwareAccelerated = true; mAttachInfo.mHardwareAccelerationRequested = true; @@ -5379,6 +5395,11 @@ public final class ViewRootImpl implements ViewParent, } } + private void updateRenderHdrSdrRatio() { + mRenderHdrSdrRatio = mDisplay.getHdrSdrRatio(); + mUpdateHdrSdrRatioInfo = true; + } + private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode) { if (mAttachInfo.mThreadedRenderer == null) { return; @@ -5396,8 +5417,7 @@ public final class ViewRootImpl implements ViewParent, float desiredRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode); if (desiredRatio != mDesiredHdrSdrRatio) { mDesiredHdrSdrRatio = desiredRatio; - mRenderHdrSdrRatio = mDisplay.getHdrSdrRatio(); - mUpdateHdrSdrRatioInfo = true; + updateRenderHdrSdrRatio(); if (mDesiredHdrSdrRatio < 1.01f) { mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener); @@ -8496,6 +8516,7 @@ public final class ViewRootImpl implements ViewParent, if (mAttachInfo.mThreadedRenderer != null) { mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); } + updateRenderHdrSdrRatio(); if (mPreviousTransformHint != transformHint) { mPreviousTransformHint = transformHint; dispatchTransformHintChanged(transformHint); @@ -8592,6 +8613,9 @@ public final class ViewRootImpl implements ViewParent, */ void getDisplayFrame(Rect outFrame) { outFrame.set(mTmpFrames.displayFrame); + // Apply sandboxing here (in getter) due to possible layout updates on the client after + // mTmpFrames.displayFrame is received from the server. + applyViewBoundsSandboxingIfNeeded(outFrame); } /** @@ -8608,6 +8632,69 @@ public final class ViewRootImpl implements ViewParent, outFrame.top += insets.top; outFrame.right -= insets.right; outFrame.bottom -= insets.bottom; + // Apply sandboxing here (in getter) due to possible layout updates on the client after + // mTmpFrames.displayFrame is received from the server. + applyViewBoundsSandboxingIfNeeded(outFrame); + } + + /** + * Offset outRect to make it sandboxed within Window's bounds. + * + * <p>This is used by {@link android.view.View#getBoundsOnScreen}, + * {@link android.view.ViewRootImpl#getDisplayFrame} and + * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by + * {@link android.view.View#getWindowDisplayFrame} and + * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as + * {@link android.view.ViewDebug#captureLayers} for debugging. + */ + void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) { + if (mViewBoundsSandboxingEnabled) { + final Rect bounds = getConfiguration().windowConfiguration.getBounds(); + inOutRect.offset(-bounds.left, -bounds.top); + } + } + + /** + * Offset outLocation to make it sandboxed within Window's bounds. + * + * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])} + */ + public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) { + if (mViewBoundsSandboxingEnabled) { + final Rect bounds = getConfiguration().windowConfiguration.getBounds(); + outLocation[0] -= bounds.left; + outLocation[1] -= bounds.top; + } + } + + private boolean getViewBoundsSandboxingEnabled() { + // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication + // may be never called. This results into all app compat changes being enabled + // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty + // array. + // With ActivityThread.isSystem we verify that it is not the system process, + // then this CompatChange can take effect. + if (ActivityThread.isSystem() + || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) { + // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled. + return false; + } + + // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer. + try { + final List<PackageManager.Property> properties = mContext.getPackageManager() + .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS); + + final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean(); + if (isOptedOut) { + // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs. + return false; + } + } catch (RuntimeException e) { + // remote exception. + } + + return true; } /** diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index a208cb3de8aa..21fe87f42e1b 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -823,6 +823,11 @@ public abstract class Window { /** @hide */ public final void destroy() { mDestroyed = true; + onDestroy(); + } + + /** @hide */ + protected void onDestroy() { } /** @hide */ diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index e7cefd60002b..35ed88fc420e 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -454,6 +454,11 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_WAKE = 11; /** + * The screen is turning off. This is used as a message to stop all animations. + * @hide + */ + int TRANSIT_SLEEP = 12; + /** * The first slot for custom transition types. Callers (like Shell) can make use of custom * transition types for dealing with special cases. These types are effectively ignored by * Core and will just be passed along as part of TransitionInfo objects. An example is @@ -462,7 +467,7 @@ public interface WindowManager extends ViewManager { * implementation. * @hide */ - int TRANSIT_FIRST_CUSTOM = 12; + int TRANSIT_FIRST_CUSTOM = 13; /** * @hide @@ -480,6 +485,7 @@ public interface WindowManager extends ViewManager { TRANSIT_KEYGUARD_UNOCCLUDE, TRANSIT_PIP, TRANSIT_WAKE, + TRANSIT_SLEEP, TRANSIT_FIRST_CUSTOM }) @Retention(RetentionPolicy.SOURCE) @@ -817,6 +823,15 @@ public interface WindowManager extends ViewManager { } /** + * If the display {@link Configuration#smallestScreenWidthDp} is greater or equal to this value, + * we will treat it as a large screen device, which will have some multi window features enabled + * by default. + * @hide + */ + @TestApi + int LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP = 600; + + /** * Application level {@link android.content.pm.PackageManager.Property PackageManager * .Property} for an app to inform the system that the app can be opted-in or opted-out * from the compatibility treatment that avoids {@link @@ -857,6 +872,42 @@ public interface WindowManager extends ViewManager { /** * Application level {@link android.content.pm.PackageManager.Property PackageManager + * .Property} for an app to inform the system that it needs to be opted-out from the + * compatibility treatment that sandboxes {@link android.view.View} API. + * + * <p>The treatment can be enabled by device manufacturers for applications which misuse + * {@link android.view.View} APIs by expecting that + * {@link android.view.View#getLocationOnScreen}, + * {@link android.view.View#getBoundsOnScreen}, + * {@link android.view.View#getWindowVisibleDisplayFrame}, + * {@link android.view.View#getWindowDisplayFrame} + * return coordinates as if an activity is positioned in the top-left corner of the screen, with + * left coordinate equal to 0. This may not be the case for applications in multi-window and in + * letterbox modes. + * + * <p>Setting this property to {@code false} informs the system that the application must be + * opted-out from the "Sandbox {@link android.view.View} API to Activity bounds" treatment even + * if the device manufacturer has opted the app into the treatment. + * + * <p>Not setting this property at all, or setting this property to {@code true} has no effect. + * + * <p><b>Syntax:</b> + * <pre> + * <application> + * <property + * android:name="android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS" + * android:value="false"/> + * </application> + * </pre> + * + * @hide + */ + // TODO(b/263984287): Make this public API. + String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS = + "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS"; + + /** + * Application level {@link android.content.pm.PackageManager.Property PackageManager * .Property} for an app to inform the system that the application can be opted-in or opted-out * from the compatibility treatment that enables sending a fake focus event for unfocused * resumed split screen activities. This is needed because some game engines wait to get @@ -1428,6 +1479,7 @@ public interface WindowManager extends ViewManager { case TRANSIT_KEYGUARD_UNOCCLUDE: return "KEYGUARD_UNOCCLUDE"; case TRANSIT_PIP: return "PIP"; case TRANSIT_WAKE: return "WAKE"; + case TRANSIT_SLEEP: return "SLEEP"; case TRANSIT_FIRST_CUSTOM: return "FIRST_CUSTOM"; default: if (type > TRANSIT_FIRST_CUSTOM) { diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 33b763bbf0c0..0acc0228ade4 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -56,7 +56,7 @@ import java.util.List; * accessibility service has not requested to retrieve the window content the event will * not contain reference to its source. <strong>Note: </strong> for events of type * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available, and Views that set - * {@link android.view.View#isAccessibilityDataPrivate()} may not populate all event properties on + * {@link android.view.View#isAccessibilityDataSensitive()} may not populate all event properties on * events sent from higher up in the view hierarchy. * </p> * <p> @@ -1168,17 +1168,17 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * set to true. * * <p> - * Initial value matches the {@link android.view.View#isAccessibilityDataPrivate} property from - * the event's source node, if present, or false by default. + * Initial value matches the {@link android.view.View#isAccessibilityDataSensitive} property + * from the event's source node, if present, or false by default. * </p> * * @return True if the event should be delivered only to isAccessibilityTool services, false * otherwise. - * @see #setAccessibilityDataPrivate + * @see #setAccessibilityDataSensitive */ @Override - public boolean isAccessibilityDataPrivate() { - return super.isAccessibilityDataPrivate(); + public boolean isAccessibilityDataSensitive() { + return super.isAccessibilityDataSensitive(); } /** @@ -1193,13 +1193,13 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * no source) then this method must be called explicitly if you want non-default behavior. * </p> * - * @param accessibilityDataPrivate True if the event should be delivered only to + * @param accessibilityDataSensitive True if the event should be delivered only to * isAccessibilityTool services, false otherwise. * @throws IllegalStateException If called from an AccessibilityService. */ @Override - public void setAccessibilityDataPrivate(boolean accessibilityDataPrivate) { - super.setAccessibilityDataPrivate(accessibilityDataPrivate); + public void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { + super.setAccessibilityDataSensitive(accessibilityDataSensitive); } /** diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 247e0262d13f..9d82b7900689 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -834,6 +834,8 @@ public class AccessibilityNodeInfo implements Parcelable { private static final int BOOLEAN_PROPERTY_REQUEST_TOUCH_PASSTHROUGH = 1 << 25; + private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 1 << 26; + /** * Bits that provide the id of a virtual descendant of a view. */ @@ -2644,6 +2646,34 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Gets if the node's accessibility data is considered sensitive. + * + * @return True if the node is editable, false otherwise. + * @see View#isAccessibilityDataSensitive() + */ + public boolean isAccessibilityDataSensitive() { + return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE); + } + + /** + * Sets whether this node's accessibility data is considered sensitive. + * + * <p> + * <strong>Note:</strong> Cannot be called from an {@link AccessibilityService}. + * This class is made immutable before being delivered to an AccessibilityService. + * </p> + * + * @param accessibilityDataSensitive True if the node's accessibility data is considered + * sensitive. + * @throws IllegalStateException If called from an AccessibilityService. + * @see View#setAccessibilityDataSensitive + */ + public void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { + setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, + accessibilityDataSensitive); + } + + /** * If this node represents a visually distinct region of the screen that may update separately * from the rest of the window, it is considered a pane. Set the pane title to indicate that * the node is a pane, and to provide a title for it. diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index 789c740bbba2..38b564ade07d 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -72,7 +72,7 @@ public class AccessibilityRecord { private static final int PROPERTY_FULL_SCREEN = 0x00000080; private static final int PROPERTY_SCROLLABLE = 0x00000100; private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200; - private static final int PROPERTY_ACCESSIBILITY_DATA_PRIVATE = 0x00000400; + private static final int PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 0x00000400; private static final int GET_SOURCE_PREFETCH_FLAGS = AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS @@ -160,8 +160,8 @@ public class AccessibilityRecord { important = root.isImportantForAccessibility(); rootViewId = root.getAccessibilityViewId(); mSourceWindowId = root.getAccessibilityWindowId(); - setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE, - root.isAccessibilityDataPrivate()); + setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, + root.isAccessibilityDataSensitive()); } setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important); mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId); @@ -391,20 +391,20 @@ public class AccessibilityRecord { } /** - * @see AccessibilityEvent#isAccessibilityDataPrivate + * @see AccessibilityEvent#isAccessibilityDataSensitive * @hide */ - boolean isAccessibilityDataPrivate() { - return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE); + boolean isAccessibilityDataSensitive() { + return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE); } /** - * @see AccessibilityEvent#setAccessibilityDataPrivate + * @see AccessibilityEvent#setAccessibilityDataSensitive * @hide */ - void setAccessibilityDataPrivate(boolean accessibilityDataPrivate) { + void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { enforceNotSealed(); - setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE, accessibilityDataPrivate); + setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, accessibilityDataSensitive); } /** @@ -962,7 +962,7 @@ public class AccessibilityRecord { appendUnless(false, PROPERTY_FULL_SCREEN, builder); appendUnless(false, PROPERTY_SCROLLABLE, builder); appendUnless(false, PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, builder); - appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_PRIVATE, builder); + appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, builder); append(builder, "BeforeText", mBeforeText); append(builder, "FromIndex", mFromIndex); @@ -996,8 +996,8 @@ public class AccessibilityRecord { case PROPERTY_SCROLLABLE: return "Scrollable"; case PROPERTY_IMPORTANT_FOR_ACCESSIBILITY: return "ImportantForAccessibility"; - case PROPERTY_ACCESSIBILITY_DATA_PRIVATE: - return "AccessibilityDataPrivate"; + case PROPERTY_ACCESSIBILITY_DATA_SENSITIVE: + return "AccessibilityDataSensitive"; default: return Integer.toHexString(prop); } } diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java index d84e0fb421cf..13ac329815f5 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java @@ -839,6 +839,7 @@ public final class AccessibilityWindowInfo implements Parcelable { mConnectionId = UNDEFINED_WINDOW_ID; mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID; mTitle = null; + mTransitionTime = 0; } /** diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index aef0e651ff8d..ab9f492694f5 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -301,6 +301,14 @@ public final class AutofillManager { public static final String EXTRA_AUGMENTED_AUTOFILL_CLIENT = "android.view.autofill.extra.AUGMENTED_AUTOFILL_CLIENT"; + /** + * Autofill Hint to indicate that it can match any field. + * + * @hide + */ + @TestApi + public static final String ANY_HINT = "any"; + private static final String SESSION_ID_TAG = "android:sessionId"; private static final String STATE_TAG = "android:state"; private static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData"; diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index b7f03e1d6d72..62044aa78213 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -182,6 +182,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** @hide */ public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10; + /** + * After {@link UPSIDE_DOWN_CAKE}, {@link #notifyViewsDisappeared(AutofillId, long[])} wraps + * the virtual children with a pair of view tree appearing and view tree appeared events. + */ @ChangeId @EnabledSince(targetSdkVersion = UPSIDE_DOWN_CAKE) static final long NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS = 258825825L; diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 6ddfcb825acc..8cff06641847 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -562,11 +562,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final int numberEvents = mEvents.size(); final String reasonString = getFlushReasonAsString(reason); - if (sDebug) { + if (sVerbose) { ContentCaptureEvent event = mEvents.get(numberEvents - 1); String forceString = (reason == FLUSH_REASON_FORCE_FLUSH) ? ". The force flush event " + ContentCaptureEvent.getTypeAsString(event.getType()) : ""; - Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason) + Log.v(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason) + forceString); } if (mFlushHistory != null) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index fd8f5495464c..1600a16566a5 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -13221,10 +13221,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { super.onPopulateAccessibilityEventInternal(event); - if (this.isAccessibilityDataPrivate() && !event.isAccessibilityDataPrivate()) { - // This view's accessibility data is private, but another view that generated this event - // is not, so don't append this view's text to the event in order to prevent sharing - // this view's contents with non-accessibility-tool services. + if (this.isAccessibilityDataSensitive() && !event.isAccessibilityDataSensitive()) { + // This view's accessibility data is sensitive, but another view that generated this + // event is not, so don't append this view's text to the event in order to prevent + // sharing this view's contents with non-accessibility-tool services. return; } diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java index a881a05a1054..fa5195727afe 100644 --- a/core/java/android/window/TaskFragmentInfo.java +++ b/core/java/android/window/TaskFragmentInfo.java @@ -66,6 +66,13 @@ public final class TaskFragmentInfo implements Parcelable { @NonNull private final List<IBinder> mActivities = new ArrayList<>(); + /** + * List of Activity tokens that were explicitly requested to be launched in this TaskFragment. + * It only contains Activities that belong to the organizer process for security. + */ + @NonNull + private final List<IBinder> mInRequestedTaskFragmentActivities = new ArrayList<>(); + /** Relative position of the fragment's top left corner in the parent container. */ private final Point mPositionInParent = new Point(); @@ -99,15 +106,18 @@ public final class TaskFragmentInfo implements Parcelable { public TaskFragmentInfo( @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, @NonNull Configuration configuration, int runningActivityCount, - boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent, - boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip, - boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions) { + boolean isVisible, @NonNull List<IBinder> activities, + @NonNull List<IBinder> inRequestedTaskFragmentActivities, + @NonNull Point positionInParent, boolean isTaskClearedForReuse, + boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront, + @NonNull Point minimumDimensions) { mFragmentToken = requireNonNull(fragmentToken); mToken = requireNonNull(token); mConfiguration.setTo(configuration); mRunningActivityCount = runningActivityCount; mIsVisible = isVisible; mActivities.addAll(activities); + mInRequestedTaskFragmentActivities.addAll(inRequestedTaskFragmentActivities); mPositionInParent.set(positionInParent); mIsTaskClearedForReuse = isTaskClearedForReuse; mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip; @@ -151,6 +161,11 @@ public final class TaskFragmentInfo implements Parcelable { return mActivities; } + @NonNull + public List<IBinder> getActivitiesRequestedInTaskFragment() { + return mInRequestedTaskFragmentActivities; + } + /** Returns the relative position of the fragment's top left corner in the parent container. */ @NonNull public Point getPositionInParent() { @@ -215,6 +230,8 @@ public final class TaskFragmentInfo implements Parcelable { && mIsVisible == that.mIsVisible && getWindowingMode() == that.getWindowingMode() && mActivities.equals(that.mActivities) + && mInRequestedTaskFragmentActivities.equals( + that.mInRequestedTaskFragmentActivities) && mPositionInParent.equals(that.mPositionInParent) && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip @@ -229,6 +246,7 @@ public final class TaskFragmentInfo implements Parcelable { mRunningActivityCount = in.readInt(); mIsVisible = in.readBoolean(); in.readBinderList(mActivities); + in.readBinderList(mInRequestedTaskFragmentActivities); mPositionInParent.readFromParcel(in); mIsTaskClearedForReuse = in.readBoolean(); mIsTaskFragmentClearedForPip = in.readBoolean(); @@ -245,6 +263,7 @@ public final class TaskFragmentInfo implements Parcelable { dest.writeInt(mRunningActivityCount); dest.writeBoolean(mIsVisible); dest.writeBinderList(mActivities); + dest.writeBinderList(mInRequestedTaskFragmentActivities); mPositionInParent.writeToParcel(dest, flags); dest.writeBoolean(mIsTaskClearedForReuse); dest.writeBoolean(mIsTaskFragmentClearedForPip); @@ -274,6 +293,7 @@ public final class TaskFragmentInfo implements Parcelable { + " runningActivityCount=" + mRunningActivityCount + " isVisible=" + mIsVisible + " activities=" + mActivities + + " inRequestedTaskFragmentActivities" + mInRequestedTaskFragmentActivities + " positionInParent=" + mPositionInParent + " isTaskClearedForReuse=" + mIsTaskClearedForReuse + " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip diff --git a/core/java/com/android/internal/app/procstats/UidState.java b/core/java/com/android/internal/app/procstats/UidState.java index 8761b7470cd3..49113465c26a 100644 --- a/core/java/com/android/internal/app/procstats/UidState.java +++ b/core/java/com/android/internal/app/procstats/UidState.java @@ -150,6 +150,7 @@ public final class UidState { public void resetSafely(long now) { mDurations.resetTable(); mStartTime = now; + mProcesses.removeIf(p -> !p.isInUse()); } /** diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java index 6c01780dac76..2a9025d35339 100644 --- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java @@ -61,7 +61,7 @@ public abstract class AbstractMultiplePendingRequestsRemoteService<S final int size = mPendingRequests.size(); if (mVerbose) Slog.v(mTag, "Sending " + size + " pending requests"); for (int i = 0; i < size; i++) { - mPendingRequests.get(i).run(); + handlePendingRequest(mPendingRequests.get(i)); } mPendingRequests.clear(); } diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index d5f7ba57a694..18414cf93bc8 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -107,7 +107,7 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I private int mServiceExitSubReason; /** Requests that have been scheduled, but that are not finished yet */ - private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>(); + protected final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>(); /** * Callback called when the service dies. @@ -673,6 +673,11 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I mCancelled = true; } + S service = mWeakService.get(); + if (service != null) { + service.finishRequest(this); + } + onCancel(); return true; } diff --git a/core/java/com/android/internal/jank/EventLogTags.logtags b/core/java/com/android/internal/jank/EventLogTags.logtags index 7af5d8fe49fc..ad47b810aa50 100644 --- a/core/java/com/android/internal/jank/EventLogTags.logtags +++ b/core/java/com/android/internal/jank/EventLogTags.logtags @@ -3,8 +3,8 @@ option java_package com.android.internal.jank; # Marks a request to start tracing a CUJ. Doesn't mean the request was executed. -37001 jank_cuj_events_begin_request (CUJ Type|1|5),(Elapsed Time Ns|2|3),(Uptime Ns|2|3) +37001 jank_cuj_events_begin_request (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Ns|2|3) # Marks a request to end tracing a CUJ. Doesn't mean the request was executed. -37002 jank_cuj_events_end_request (CUJ Type|1|5),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3) +37002 jank_cuj_events_end_request (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3) # Marks a request to cancel tracing a CUJ. Doesn't mean the request was executed. -37003 jank_cuj_events_cancel_request (CUJ Type|1|5),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3) +37003 jank_cuj_events_cancel_request (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3) diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index d93fff98254b..7ae63b1ac450 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -128,6 +128,7 @@ import com.android.internal.util.PerfettoTrigger; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.Instant; import java.util.Locale; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -578,8 +579,10 @@ public class InteractionJankMonitor { public boolean begin(@NonNull Configuration.Builder builder) { try { final Configuration config = builder.build(); - EventLogTags.writeJankCujEventsBeginRequest( - config.mCujType, SystemClock.elapsedRealtimeNanos(), SystemClock.uptimeNanos()); + postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> { + EventLogTags.writeJankCujEventsBeginRequest( + config.mCujType, unixNanos, elapsedNanos, realtimeNanos); + }); final TrackerResult result = new TrackerResult(); final boolean success = config.getHandler().runWithScissors( () -> result.mResult = beginInternal(config), EXECUTOR_TASK_TIMEOUT); @@ -653,8 +656,10 @@ public class InteractionJankMonitor { * @return boolean true if the tracker is ended successfully, false otherwise. */ public boolean end(@CujType int cujType) { - EventLogTags.writeJankCujEventsEndRequest(cujType, SystemClock.elapsedRealtimeNanos(), - SystemClock.uptimeNanos()); + postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> { + EventLogTags.writeJankCujEventsEndRequest( + cujType, unixNanos, elapsedNanos, realtimeNanos); + }); FrameTracker tracker = getTracker(cujType); // Skip this call since we haven't started a trace yet. if (tracker == null) return false; @@ -692,8 +697,10 @@ public class InteractionJankMonitor { * @return boolean true if the tracker is cancelled successfully, false otherwise. */ public boolean cancel(@CujType int cujType) { - EventLogTags.writeJankCujEventsCancelRequest(cujType, SystemClock.elapsedRealtimeNanos(), - SystemClock.uptimeNanos()); + postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> { + EventLogTags.writeJankCujEventsCancelRequest( + cujType, unixNanos, elapsedNanos, realtimeNanos); + }); return cancel(cujType, REASON_CANCEL_NORMAL); } @@ -951,7 +958,7 @@ public class InteractionJankMonitor { case CUJ_IME_INSETS_ANIMATION: return "IME_INSETS_ANIMATION"; case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION: - return "CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION"; + return "LOCKSCREEN_CLOCK_MOVE_ANIMATION"; } return "UNKNOWN"; } @@ -1284,4 +1291,21 @@ public class InteractionJankMonitor { return mReason; } } + + @FunctionalInterface + private interface TimeFunction { + void invoke(long unixNanos, long elapsedNanos, long realtimeNanos); + } + + private void postEventLogToWorkerThread(TimeFunction logFunction) { + final Instant now = Instant.now(); + final long unixNanos = TimeUnit.NANOSECONDS.convert(now.getEpochSecond(), TimeUnit.SECONDS) + + now.getNano(); + final long elapsedNanos = SystemClock.elapsedRealtimeNanos(); + final long realtimeNanos = SystemClock.uptimeNanos(); + + mWorker.getThreadHandler().post(() -> { + logFunction.invoke(unixNanos, elapsedNanos, realtimeNanos); + }); + } } diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 65655b7b5a66..70514c30d90d 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -80,10 +80,6 @@ public class ProcessCpuTracker { /** Stores user time and system time in jiffies. */ private final long[] mProcessStatsData = new long[4]; - /** Stores user time and system time in jiffies. Used for - * public API to retrieve CPU use for a process. Must lock while in use. */ - private final long[] mSinglePidStatsData = new long[4]; - private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] { PROC_SPACE_TERM, PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 2: name @@ -629,17 +625,15 @@ public class ProcessCpuTracker { * executing in both user and system code. Safe to call without lock held. */ public long getCpuTimeForPid(int pid) { - synchronized (mSinglePidStatsData) { - final String statFile = "/proc/" + pid + "/stat"; - final long[] statsData = mSinglePidStatsData; - if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT, - null, statsData, null)) { - long time = statsData[PROCESS_STAT_UTIME] + final String statFile = "/proc/" + pid + "/stat"; + final long[] statsData = new long[4]; + if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT, + null, statsData, null)) { + long time = statsData[PROCESS_STAT_UTIME] + statsData[PROCESS_STAT_STIME]; - return time * mJiffyMillis; - } - return 0; + return time * mJiffyMillis; } + return 0; } /** @@ -647,15 +641,13 @@ public class ProcessCpuTracker { * in the runqueue. Safe to call without lock held. */ public long getCpuDelayTimeForPid(int pid) { - synchronized (mSinglePidStatsData) { - final String statFile = "/proc/" + pid + "/schedstat"; - final long[] statsData = mSinglePidStatsData; - if (Process.readProcFile(statFile, PROCESS_SCHEDSTATS_FORMAT, - null, statsData, null)) { - return statsData[PROCESS_SCHEDSTAT_CPU_DELAY_TIME] / 1_000_000; - } - return 0; + final String statFile = "/proc/" + pid + "/schedstat"; + final long[] statsData = new long[4]; + if (Process.readProcFile(statFile, PROCESS_SCHEDSTATS_FORMAT, + null, statsData, null)) { + return statsData[PROCESS_SCHEDSTAT_CPU_DELAY_TIME] / 1_000_000; } + return 0; } /** diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index c41b8223d181..9b9e010039a6 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -295,6 +295,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean mClosingActionMenu; private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; + private int mAudioMode = AudioManager.MODE_NORMAL; private MediaController mMediaController; private AudioManager mAudioManager; @@ -317,6 +318,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } }; + private AudioManager.OnModeChangedListener mOnModeChangedListener; + private Transition mEnterTransition = null; private Transition mReturnTransition = USE_DEFAULT_TRANSITION; private Transition mExitTransition = null; @@ -1944,7 +1947,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_VOLUME_MUTE: { // If we have a session and no active phone call send it the volume command, // otherwise use the suggested stream. - if (mMediaController != null && !isActivePhoneCallKnown()) { + if (mMediaController != null && !isActivePhoneCallOngoing()) { getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event, mMediaController.getSessionToken()); } else { @@ -1995,16 +1998,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } - private boolean isActivePhoneCallKnown() { - boolean isActivePhoneCallKnown = false; - AudioManager audioManager = - (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - int audioManagerMode = audioManager.getMode(); - if (audioManagerMode == AudioManager.MODE_IN_CALL - || audioManagerMode == AudioManager.MODE_IN_COMMUNICATION) { - isActivePhoneCallKnown = true; - } - return isActivePhoneCallKnown; + private boolean isActivePhoneCallOngoing() { + return mAudioMode == AudioManager.MODE_IN_CALL + || mAudioMode == AudioManager.MODE_IN_COMMUNICATION; } private KeyguardManager getKeyguardManager() { @@ -2331,6 +2327,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + protected void onDestroy() { + if (mOnModeChangedListener != null) { + getAudioManager().removeOnModeChangedListener(mOnModeChangedListener); + mOnModeChangedListener = null; + } + } + private class PanelMenuPresenterCallback implements MenuPresenter.Callback { @Override public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { @@ -3229,6 +3233,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void setMediaController(MediaController controller) { mMediaController = controller; + if (controller != null && mOnModeChangedListener == null) { + mAudioMode = getAudioManager().getMode(); + mOnModeChangedListener = mode -> mAudioMode = mode; + getAudioManager().addOnModeChangedListener(getContext().getMainExecutor(), + mOnModeChangedListener); + } else if (mOnModeChangedListener != null) { + getAudioManager().removeOnModeChangedListener(mOnModeChangedListener); + mOnModeChangedListener = null; + } } @Override diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java index f2b0544bcfad..abe6c7c079c2 100644 --- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java @@ -72,11 +72,13 @@ public class BaseProtoLogImpl { private static final String TAG = "ProtoLog"; private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; static final String PROTOLOG_VERSION = "1.0.0"; + private static final int DEFAULT_PER_CHUNK_SIZE = 0; private final File mLogFile; private final String mViewerConfigFilename; private final TraceBuffer mBuffer; protected final ProtoLogViewerConfigReader mViewerConfig; + private final int mPerChunkSize; private boolean mProtoLogEnabled; private boolean mProtoLogEnabledLockFree; @@ -160,7 +162,7 @@ public class BaseProtoLogImpl { return; } try { - ProtoOutputStream os = new ProtoOutputStream(); + ProtoOutputStream os = new ProtoOutputStream(mPerChunkSize); long token = os.start(LOG); os.write(MESSAGE_HASH, messageHash); os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); @@ -219,10 +221,16 @@ public class BaseProtoLogImpl { public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) { + this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE); + } + + public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, + ProtoLogViewerConfigReader viewerConfig, int perChunkSize) { mLogFile = file; mBuffer = new TraceBuffer(bufferCapacity); mViewerConfigFilename = viewerConfigFilename; mViewerConfig = viewerConfig; + mPerChunkSize = perChunkSize; } /** @@ -368,7 +376,7 @@ public class BaseProtoLogImpl { try { long offset = (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000)); - ProtoOutputStream proto = new ProtoOutputStream(); + ProtoOutputStream proto = new ProtoOutputStream(mPerChunkSize); proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); proto.write(VERSION, PROTOLOG_VERSION); proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset); diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 353c6c083d9d..527cfddf6d8e 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -30,6 +30,7 @@ public class ProtoLogImpl extends BaseProtoLogImpl { private static final int BUFFER_CAPACITY = 1024 * 1024; private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope"; private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz"; + private static final int PER_CHUNK_SIZE = 1024; private static ProtoLogImpl sServiceInstance = null; @@ -94,7 +95,10 @@ public class ProtoLogImpl extends BaseProtoLogImpl { public static synchronized ProtoLogImpl getSingleInstance() { if (sServiceInstance == null) { sServiceInstance = new ProtoLogImpl( - new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader()); + new File(LOG_FILENAME) + , BUFFER_CAPACITY + , new ProtoLogViewerConfigReader() + , PER_CHUNK_SIZE); } return sServiceInstance; } @@ -105,8 +109,8 @@ public class ProtoLogImpl extends BaseProtoLogImpl { } public ProtoLogImpl(File logFile, int bufferCapacity, - ProtoLogViewerConfigReader viewConfigReader) { - super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader); - } + ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) { + super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize); + } } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 59f6d2b29481..b86020eb90ea 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -133,6 +133,21 @@ public class LockPatternUtils { }) public @interface CredentialType {} + public static String credentialTypeToString(int credentialType) { + switch (credentialType) { + case CREDENTIAL_TYPE_NONE: + return "NONE"; + case CREDENTIAL_TYPE_PATTERN: + return "PATTERN"; + case CREDENTIAL_TYPE_PIN: + return "PIN"; + case CREDENTIAL_TYPE_PASSWORD: + return "PASSWORD"; + default: + return "UNKNOWN_" + credentialType; + } + } + /** * Flag provided to {@link #verifyCredential(LockscreenCredential, int, int)} . If set, the * method will return a handle to the Gatekeeper Password in the diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index b09a9c3a505d..739055e040af 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -50,12 +50,22 @@ static struct { struct { jclass clazz; + jmethodID init; + + jfieldID vsyncId; + jfieldID expectedPresentationTime; + jfieldID deadline; } frameTimelineClassInfo; struct { jclass clazz; + jmethodID init; + + jfieldID frameInterval; + jfieldID preferredFrameTimelineIndex; + jfieldID frameTimelines; } vsyncEventDataClassInfo; } gDisplayEventReceiverClassInfo; @@ -63,7 +73,7 @@ static struct { class NativeDisplayEventReceiver : public DisplayEventDispatcher { public: - NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, + NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource, jint eventRegistration, jlong layerHandle); @@ -74,6 +84,7 @@ protected: private: jobject mReceiverWeakGlobal; + jobject mVsyncEventDataWeakGlobal; sp<MessageQueue> mMessageQueue; void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, @@ -87,6 +98,7 @@ private: }; NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, + jobject vsyncEventDataWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource, jint eventRegistration, jlong layerHandle) @@ -98,6 +110,7 @@ NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject rece reinterpret_cast<IBinder*>(layerHandle)) : nullptr), mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), + mVsyncEventDataWeakGlobal(env->NewGlobalRef(vsyncEventDataWeak)), mMessageQueue(messageQueue) { ALOGV("receiver %p ~ Initializing display event receiver.", this); } @@ -144,12 +157,39 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla JNIEnv* env = AndroidRuntime::getJNIEnv(); ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); - if (receiverObj.get()) { + ScopedLocalRef<jobject> vsyncEventDataObj(env, GetReferent(env, mVsyncEventDataWeakGlobal)); + if (receiverObj.get() && vsyncEventDataObj.get()) { ALOGV("receiver %p ~ Invoking vsync handler.", this); - jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData); + env->SetIntField(vsyncEventDataObj.get(), + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo + .preferredFrameTimelineIndex, + vsyncEventData.preferredFrameTimelineIndex); + env->SetLongField(vsyncEventDataObj.get(), + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval, + vsyncEventData.frameInterval); + + jobjectArray frameTimelinesObj = reinterpret_cast<jobjectArray>( + env->GetObjectField(vsyncEventDataObj.get(), + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo + .frameTimelines)); + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i]; + jobject frameTimelineObj = env->GetObjectArrayElement(frameTimelinesObj, i); + env->SetLongField(frameTimelineObj, + gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId, + frameTimeline.vsyncId); + env->SetLongField(frameTimelineObj, + gDisplayEventReceiverClassInfo.frameTimelineClassInfo + .expectedPresentationTime, + frameTimeline.expectedPresentationTime); + env->SetLongField(frameTimelineObj, + gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline, + frameTimeline.deadlineTimestamp); + } + env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, - timestamp, displayId.value, count, javaVsyncEventData); + timestamp, displayId.value, count); ALOGV("receiver %p ~ Returned from vsync handler.", this); } @@ -217,8 +257,9 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides( mMessageQueue->raiseAndClearException(env, "dispatchModeChanged"); } -static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj, - jint vsyncSource, jint eventRegistration, jlong layerHandle) { +static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak, + jobject messageQueueObj, jint vsyncSource, jint eventRegistration, + jlong layerHandle) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); @@ -226,8 +267,8 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject } sp<NativeDisplayEventReceiver> receiver = - new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource, - eventRegistration, layerHandle); + new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue, + vsyncSource, eventRegistration, layerHandle); status_t status = receiver->initialize(); if (status) { String8 message; @@ -274,7 +315,9 @@ static jobject nativeGetLatestVsyncEventData(JNIEnv* env, jclass clazz, jlong re static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - {"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;IIJ)J", + {"nativeInit", + "(Ljava/lang/ref/WeakReference;Ljava/lang/ref/WeakReference;Landroid/os/" + "MessageQueue;IIJ)J", (void*)nativeInit}, {"nativeGetDisplayEventReceiverFinalizer", "()J", (void*)nativeGetDisplayEventReceiverFinalizer}, @@ -291,8 +334,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); gDisplayEventReceiverClassInfo.dispatchVsync = - GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", - "(JJILandroid/view/DisplayEventReceiver$VsyncEventData;)V"); + GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V"); gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V"); gDisplayEventReceiverClassInfo.dispatchModeChanged = @@ -318,6 +360,15 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz, "<init>", "(JJJ)V"); + gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz, + "vsyncId", "J"); + gDisplayEventReceiverClassInfo.frameTimelineClassInfo.expectedPresentationTime = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz, + "expectedPresentationTime", "J"); + gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz, + "deadline", "J"); jclass vsyncEventDataClazz = FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData"); @@ -329,6 +380,17 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { "([Landroid/view/" "DisplayEventReceiver$VsyncEventData$FrameTimeline;IJ)V"); + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, + "preferredFrameTimelineIndex", "I"); + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, + "frameInterval", "J"); + gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelines = + GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz, + "frameTimelines", + "[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;"); + return res; } diff --git a/core/jni/android_view_MotionPredictor.cpp b/core/jni/android_view_MotionPredictor.cpp index 2c232fadbbc5..de3e81c7088b 100644 --- a/core/jni/android_view_MotionPredictor.cpp +++ b/core/jni/android_view_MotionPredictor.cpp @@ -20,7 +20,6 @@ #include <input/MotionPredictor.h> #include "android_view_MotionEvent.h" -#include "core_jni_converters.h" #include "core_jni_helpers.h" /** @@ -30,14 +29,6 @@ namespace android { -// ---------------------------------------------------------------------------- - -static struct { - jclass clazz; -} gMotionEventClassInfo; - -// ---------------------------------------------------------------------------- - static void release(void* ptr) { delete reinterpret_cast<MotionPredictor*>(ptr); } @@ -57,14 +48,20 @@ static void android_view_MotionPredictor_nativeRecord(JNIEnv* env, jclass clazz, jobject event) { MotionPredictor* predictor = reinterpret_cast<MotionPredictor*>(ptr); MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, event); - predictor->record(*motionEvent); + + android::base::Result<void> result = predictor->record(*motionEvent); + if (!result.ok()) { + jniThrowException(env, "java/lang/IllegalArgumentException", + result.error().message().c_str()); + } } static jobject android_view_MotionPredictor_nativePredict(JNIEnv* env, jclass clazz, jlong ptr, jlong predictionTimeNanos) { MotionPredictor* predictor = reinterpret_cast<MotionPredictor*>(ptr); - return toJavaArray(env, predictor->predict(static_cast<nsecs_t>(predictionTimeNanos)), - gMotionEventClassInfo.clazz, &android_view_MotionEvent_obtainFromNative); + return android_view_MotionEvent_obtainFromNative(env, + predictor->predict(static_cast<nsecs_t>( + predictionTimeNanos))); } static jboolean android_view_MotionPredictor_nativeIsPredictionAvailable(JNIEnv* env, jclass clazz, @@ -84,15 +81,13 @@ static const std::array<JNINativeMethod, 5> gMotionPredictorMethods{{ (void*)android_view_MotionPredictor_nativeGetNativeMotionPredictorFinalizer}, {"nativeRecord", "(JLandroid/view/MotionEvent;)V", (void*)android_view_MotionPredictor_nativeRecord}, - {"nativePredict", "(JJ)[Landroid/view/MotionEvent;", + {"nativePredict", "(JJ)Landroid/view/MotionEvent;", (void*)android_view_MotionPredictor_nativePredict}, {"nativeIsPredictionAvailable", "(JII)Z", (void*)android_view_MotionPredictor_nativeIsPredictionAvailable}, }}; int register_android_view_MotionPredictor(JNIEnv* env) { - jclass motionEventClazz = FindClassOrDie(env, "android/view/MotionEvent"); - gMotionEventClassInfo.clazz = MakeGlobalRefOrDie(env, motionEventClazz); return RegisterMethodsOrDie(env, "android/view/MotionPredictor", gMotionPredictorMethods.data(), gMotionPredictorMethods.size()); } diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 8caf12773260..a5d287c3e4b2 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -95,6 +95,8 @@ message SecureSettingsProto { optional SettingProto hearing_aid_media_routing = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto hearing_aid_system_sounds_routing = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_magnification_joystick_enabled = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Settings for font scaling + optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto index 146ac9d2c425..7503dde440e0 100644 --- a/core/proto/android/providers/settings/system.proto +++ b/core/proto/android/providers/settings/system.proto @@ -115,6 +115,9 @@ message SystemSettingsProto { optional SettingProto sound_cache = 2; optional SettingProto light_pulse = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto vibration_intensity = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto camera_flash_notification = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_flash_notification = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_flash_notification_color_global = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Notification notification = 17; diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index ab7b0ab8d1fc..ed612a05e6b5 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -142,6 +142,7 @@ message BroadcastQueueProto { optional int64 finish_clock_time_ms = 4; } repeated BroadcastSummary historical_broadcasts_summary = 6; + repeated BroadcastRecordProto pending_broadcasts = 7; } message MemInfoDumpProto { @@ -439,6 +440,7 @@ message ServiceRecordProto { optional int32 id = 1; optional .android.app.NotificationProto notification = 2; + optional int32 foregroundServiceType = 3; } optional Foreground foreground = 13; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 85d17650289a..cb6c09241807 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -822,6 +822,8 @@ <protected-broadcast android:name="com.android.internal.telephony.cat.SMS_SENT_ACTION" /> <protected-broadcast android:name="com.android.internal.telephony.cat.SMS_DELIVERY_ACTION" /> <protected-broadcast android:name="android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED" /> + <protected-broadcast android:name="com.android.internal.intent.action.FLASH_NOTIFICATION_START_PREVIEW" /> + <protected-broadcast android:name="com.android.internal.intent.action.FLASH_NOTIFICATION_STOP_PREVIEW" /> <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> @@ -3707,7 +3709,8 @@ <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.--> <permission android:name="android.permission.PROVISION_DEMO_DEVICE" - android:protectionLevel="signature|setup" /> + android:protectionLevel="signature|setup|knownSigner" + android:knownCerts="@array/demo_device_provisioning_known_signers" /> <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze periods. --> @@ -4481,8 +4484,8 @@ <!-- Allows an application to be able to store and retrieve credentials from a remote device. @hide @SystemApi --> - <permission android:name="android.permission.PROVIDE_HYBRID_CREDENTIAL_SERVICE" - android:protectionLevel="signature|privileged" /> + <permission android:name="android.permission.PROVIDE_REMOTE_CREDENTIALS" + android:protectionLevel="signature|privileged|role" /> <!-- ========================================= --> <!-- Permissions for special development tools --> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 76b39bb5c180..70464d830c0b 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -207,12 +207,9 @@ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplikazio pertsonalak blokeatuta egongo dira laneko profila aktibatzen duzun arte"</string> <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplikazio pertsonalak egun eta ordu honetan blokeatuko dira: <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. IKT saileko administratzaileak ez dizu ematen baimenik laneko profila <xliff:g id="NUMBER">%3$d</xliff:g> egunez baino gehiagoz desaktibatuta edukitzeko."</string> <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktibatu"</string> - <!-- no translation found for work_profile_telephony_paused_title (7690804479291839519) --> - <skip /> - <!-- no translation found for work_profile_telephony_paused_text (8065762301100978221) --> - <skip /> - <!-- no translation found for work_profile_telephony_paused_turn_on_button (7542632318337068821) --> - <skip /> + <string name="work_profile_telephony_paused_title" msgid="7690804479291839519">"Deiak eta mezuak desaktibatuta daude"</string> + <string name="work_profile_telephony_paused_text" msgid="8065762301100978221">"Laneko aplikazioak pausatu dituzu. Ez duzu jasoko telefono-deirik edo testu-mezurik."</string> + <string name="work_profile_telephony_paused_turn_on_button" msgid="7542632318337068821">"Berraktibatu laneko aplikazioak"</string> <string name="me" msgid="6207584824693813140">"Ni"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletaren aukerak"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV gailuaren aukerak"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index dfb0b2e9f3a3..562560e00b11 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -296,7 +296,7 @@ <string name="safeMode" msgid="8974401416068943888">"حالت ایمن"</string> <string name="android_system_label" msgid="5974767339591067210">"سیستم Android"</string> <string name="user_owner_label" msgid="8628726904184471211">"جابهجا شدن به نمایه شخصی"</string> - <string name="managed_profile_label" msgid="7316778766973512382">"جابهجا شدن به نمایه کاری"</string> + <string name="managed_profile_label" msgid="7316778766973512382">"رفتن به نمایه کاری"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"مخاطبین"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"دسترسی به مخاطبین شما"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"مکان"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 0c4dfaec5c82..b8a364b1fbd4 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -208,12 +208,9 @@ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles sont bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string> <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à laisser votre profil professionnel désactivé pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string> <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activer"</string> - <!-- no translation found for work_profile_telephony_paused_title (7690804479291839519) --> - <skip /> - <!-- no translation found for work_profile_telephony_paused_text (8065762301100978221) --> - <skip /> - <!-- no translation found for work_profile_telephony_paused_turn_on_button (7542632318337068821) --> - <skip /> + <string name="work_profile_telephony_paused_title" msgid="7690804479291839519">"Les appels et messages sont désactivés"</string> + <string name="work_profile_telephony_paused_text" msgid="8065762301100978221">"Vous avez mis en pause les applications professionnelles. Vous ne recevrez aucun appel téléphonique ni message texte."</string> + <string name="work_profile_telephony_paused_turn_on_button" msgid="7542632318337068821">"Réact. applis prof."</string> <string name="me" msgid="6207584824693813140">"Moi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Options d\'Android TV"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 706e92076ceb..7169464a9eac 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1960,7 +1960,7 @@ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string> <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Անհրաժեշտ է թույլտվություն"</string> <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Տեսախցիկն անհասանելի է"</string> - <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string> + <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string> <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Խոսափողն անհասանելի է"</string> <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Խանութը հասանելի չէ"</string> <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-ի կարգավորումներն անհասանելի են"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index bd29ffb10129..a5878646264d 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1985,7 +1985,7 @@ <string name="profile_encrypted_message" msgid="1128512616293157802">"Tocca per sbloc. prof. di lav."</string> <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Connesso a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Tocca per visualizzare i file"</string> - <string name="pin_target" msgid="8036028973110156895">"Blocca"</string> + <string name="pin_target" msgid="8036028973110156895">"Fissa"</string> <string name="pin_specific_target" msgid="7824671240625957415">"Blocca <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="unpin_target" msgid="3963318576590204447">"Sgancia"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Sblocca <xliff:g id="LABEL">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 8064eb04949e..348dcd502a97 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -207,12 +207,9 @@ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"직장 프로필을 사용 설정할 때까지 개인 앱이 차단됩니다."</string> <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"개인 앱이 <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>에 차단됩니다. IT 관리자가 <xliff:g id="NUMBER">%3$d</xliff:g>일 넘게 직장 프로필을 중지하도록 허용하지 않습니다."</string> <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"사용 설정"</string> - <!-- no translation found for work_profile_telephony_paused_title (7690804479291839519) --> - <skip /> - <!-- no translation found for work_profile_telephony_paused_text (8065762301100978221) --> - <skip /> - <!-- no translation found for work_profile_telephony_paused_turn_on_button (7542632318337068821) --> - <skip /> + <string name="work_profile_telephony_paused_title" msgid="7690804479291839519">"전화 및 메시지 사용 중지됨"</string> + <string name="work_profile_telephony_paused_text" msgid="8065762301100978221">"직장 앱을 일시중지했습니다. 전화나 문자 메시지를 수신하지 않습니다."</string> + <string name="work_profile_telephony_paused_turn_on_button" msgid="7542632318337068821">"직장 앱 일시중지 해제"</string> <string name="me" msgid="6207584824693813140">"나"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"태블릿 옵션"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 옵션"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 3888e0c527c0..047d126aaaf7 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1172,8 +1172,8 @@ <string name="no" msgid="5122037903299899715">"Отмена"</string> <string name="dialog_alert_title" msgid="651856561974090712">"Внимание!"</string> <string name="loading" msgid="3138021523725055037">"Загрузка…"</string> - <string name="capital_on" msgid="2770685323900821829">"I"</string> - <string name="capital_off" msgid="7443704171014626777">"O"</string> + <string name="capital_on" msgid="2770685323900821829">"Включено"</string> + <string name="capital_off" msgid="7443704171014626777">"Выключено"</string> <string name="checked" msgid="9179896827054513119">"отмечено"</string> <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string> <string name="selected" msgid="6614607926197755875">"выбрано"</string> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index 4468ebe90ba0..b35481d3c31b 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -227,4 +227,10 @@ <string-array name="device_state_notification_thermal_contents"> <item>@string/concurrent_display_notification_thermal_content</item> </string-array> + + <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner of the + demo device provisioning permissions. --> + <string-array name="demo_device_provisioning_known_signers"> + <item>@string/config_retailDemoPackageSignature</item> + </string-array> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9252b149797b..2a67b44d6416 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3201,8 +3201,8 @@ <!-- Describes whether this view should allow interactions from AccessibilityServices only if the service sets the isAccessibilityTool property. --> - <attr name="accessibilityDataPrivate" format="integer"> - <!-- The system determines whether the view's accessibility data is private + <attr name="accessibilityDataSensitive" format="integer"> + <!-- The system determines whether the view's accessibility data is sensitive - default (recommended). --> <enum name="auto" value="0" /> <!-- Allow interactions from AccessibilityServices only if the service sets the diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 733e0eacc258..ffb602d93b0f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3988,7 +3988,7 @@ <!-- Whether the device supports non-resizable activity in multi windowing modes. -1: The device doesn't support non-resizable in multi windowing modes. 0: The device supports non-resizable in multi windowing modes only if this is a large - screen (smallest width >= {@link config_largeScreenSmallestScreenWidthDp}). + screen (smallest width >= {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}). 1: The device always supports non-resizable in multi windowing modes. --> <integer name="config_supportsNonResizableMultiWindow">0</integer> @@ -3998,9 +3998,9 @@ -1: The device ignores the activity min width/height when determining if it can be shown in multi windowing modes. 0: If this is a small screen (smallest width < - {@link config_largeScreenSmallestScreenWidthDp}), the device compares the activity min - width/height with the min multi windowing modes dimensions the device supports to - determine if the activity can be shown in multi windowing modes + {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}), the device compares the + activity min width/height with the min multi windowing modes dimensions the device + supports to determine if the activity can be shown in multi windowing modes 1: The device always compare the activity min width/height with the min multi windowing modes dimensions {@link config_minPercentageMultiWindowSupportWidth} the device supports to determine if the activity can be shown in multi windowing modes. @@ -4023,11 +4023,6 @@ --> <item name="config_minPercentageMultiWindowSupportWidth" format="float" type="dimen">0.5</item> - <!-- If the display smallest screen width is greater or equal to this value, we will treat it - as a large screen device, which will have some multi window features enabled by default. - --> - <integer name="config_largeScreenSmallestScreenWidthDp">600</integer> - <!-- True if the device is using legacy split. --> <bool name="config_useLegacySplit">false</bool> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 973b3a76c956..ebda172061d3 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -123,7 +123,7 @@ <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" /> <!-- Whether using the new SubscriptionManagerService or the old SubscriptionController --> - <bool name="config_using_subscription_manager_service">false</bool> + <bool name="config_using_subscription_manager_service">true</bool> <java-symbol type="bool" name="config_using_subscription_manager_service" /> <!-- Whether asynchronously update the subscription database or not. Async mode increases diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index ee021001a54a..69d5feff2de9 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -114,7 +114,7 @@ <public name="handwritingBoundsOffsetTop" /> <public name="handwritingBoundsOffsetRight" /> <public name="handwritingBoundsOffsetBottom" /> - <public name="accessibilityDataPrivate" /> + <public name="accessibilityDataSensitive" /> <public name="enableTextStylingShortcuts" /> <public name="requiredDisplayCategory"/> <public name="removed_maxConcurrentSessionsCount" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 47d771fea12d..07f353025f87 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4746,8 +4746,7 @@ <string name="accessibility_shortcut_disabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned off.</string> <!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] --> - <string name="accessibility_shortcut_spoken_feedback">Press and hold both volume keys for three seconds to use - <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g></string> + <string name="accessibility_shortcut_spoken_feedback">Release the volume keys. To turn on <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g>, press and hold both volume keys again for 3 seconds.</string> <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. [CHAR LIMIT=none]--> <string name="accessibility_button_prompt_text">Choose a feature to use when you tap the accessibility button:</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e2b46d017288..92dc5694ff2c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -405,7 +405,6 @@ <java-symbol type="integer" name="config_respectsActivityMinWidthHeightMultiWindow" /> <java-symbol type="dimen" name="config_minPercentageMultiWindowSupportHeight" /> <java-symbol type="dimen" name="config_minPercentageMultiWindowSupportWidth" /> - <java-symbol type="integer" name="config_largeScreenSmallestScreenWidthDp" /> <java-symbol type="bool" name="config_useLegacySplit" /> <java-symbol type="bool" name="config_noHomeScreen" /> <java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" /> diff --git a/core/res/res/xml/irq_device_map.xml b/core/res/res/xml/irq_device_map.xml index 86a44d6a9fe0..4fae8fb77687 100644 --- a/core/res/res/xml/irq_device_map.xml +++ b/core/res/res/xml/irq_device_map.xml @@ -17,14 +17,15 @@ */ --> <irq-device-map> - <!-- This file maps devices (chips) that can send IRQs to the CPU (and bring it out of sleep) to - logical subsystems in userspace code. Since each Android device has its own uniquely - designed chipset, this mapping is expected to be empty by default and should be overridden - by device specific configs. + <!-- This file maps devices (chips) that can send interrupts to the main processor (and bring it + out of sleep) to logical subsystems in userspace code. Since each Android device has its own + uniquely designed chipset, this mapping is expected to be empty by default and should be + overridden by device-specific configs. This mapping helps the system to meaningfully attribute CPU wakeups to logical work that happened on the device. The devices are referred to by their names as defined in the kernel. - Currently defined subsystems are: + Currently, defined subsystems are: - Alarm: Use this to denote wakeup alarms requested by apps via the AlarmManager API. + - Wifi: Use this to denote network traffic that uses the wifi transport. The overlay should use tags <device> and <subsystem> to describe this mapping in the following way: diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java deleted file mode 100644 index 16ed3ef42da3..000000000000 --- a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 android.companion.virtual.sensor; - -import static android.hardware.Sensor.TYPE_ACCELEROMETER; -import static android.hardware.SensorDirectChannel.RATE_STOP; -import static android.hardware.SensorDirectChannel.RATE_VERY_FAST; -import static android.hardware.SensorDirectChannel.TYPE_HARDWARE_BUFFER; -import static android.hardware.SensorDirectChannel.TYPE_MEMORY_FILE; - -import static com.google.common.truth.Truth.assertThat; - -import static org.testng.Assert.assertThrows; - -import android.os.Parcel; -import android.platform.test.annotations.Presubmit; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@Presubmit -@RunWith(AndroidJUnit4.class) -public class VirtualSensorConfigTest { - - private static final String SENSOR_NAME = "VirtualSensorName"; - private static final String SENSOR_VENDOR = "VirtualSensorVendor"; - - @Test - public void parcelAndUnparcel_matches() { - final VirtualSensorConfig originalConfig = - new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME) - .setVendor(SENSOR_VENDOR) - .setHighestDirectReportRateLevel(RATE_VERY_FAST) - .setDirectChannelTypesSupported(TYPE_MEMORY_FILE) - .build(); - final Parcel parcel = Parcel.obtain(); - originalConfig.writeToParcel(parcel, /* flags= */ 0); - parcel.setDataPosition(0); - final VirtualSensorConfig recreatedConfig = - VirtualSensorConfig.CREATOR.createFromParcel(parcel); - assertThat(recreatedConfig.getType()).isEqualTo(originalConfig.getType()); - assertThat(recreatedConfig.getName()).isEqualTo(originalConfig.getName()); - assertThat(recreatedConfig.getVendor()).isEqualTo(originalConfig.getVendor()); - assertThat(recreatedConfig.getHighestDirectReportRateLevel()).isEqualTo(RATE_VERY_FAST); - assertThat(recreatedConfig.getDirectChannelTypesSupported()).isEqualTo(TYPE_MEMORY_FILE); - // From hardware/libhardware/include/hardware/sensors-base.h: - // 0x400 is SENSOR_FLAG_DIRECT_CHANNEL_ASHMEM (i.e. TYPE_MEMORY_FILE) - // 0x800 is SENSOR_FLAG_DIRECT_CHANNEL_GRALLOC (i.e. TYPE_HARDWARE_BUFFER) - // 7 is SENSOR_FLAG_SHIFT_DIRECT_REPORT - assertThat(recreatedConfig.getFlags()).isEqualTo(0x400 | RATE_VERY_FAST << 7); - } - - @Test - public void hardwareBufferDirectChannelTypeSupported_throwsException() { - assertThrows( - IllegalArgumentException.class, - () -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME) - .setDirectChannelTypesSupported(TYPE_HARDWARE_BUFFER | TYPE_MEMORY_FILE)); - } - - @Test - public void directChannelTypeSupported_missingHighestReportRateLevel_throwsException() { - assertThrows( - IllegalArgumentException.class, - () -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME) - .setDirectChannelTypesSupported(TYPE_MEMORY_FILE) - .build()); - } - - @Test - public void directChannelTypeSupported_missingDirectChannelTypeSupported_throwsException() { - assertThrows( - IllegalArgumentException.class, - () -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME) - .setHighestDirectReportRateLevel(RATE_VERY_FAST) - .build()); - } - - @Test - public void sensorConfig_onlyRequiredFields() { - final VirtualSensorConfig config = - new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME).build(); - assertThat(config.getVendor()).isNull(); - assertThat(config.getHighestDirectReportRateLevel()).isEqualTo(RATE_STOP); - assertThat(config.getDirectChannelTypesSupported()).isEqualTo(0); - assertThat(config.getFlags()).isEqualTo(0); - } -} diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java deleted file mode 100644 index c260ef90cd4e..000000000000 --- a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 android.companion.virtual.sensor; - -import static com.google.common.truth.Truth.assertThat; - -import static org.testng.Assert.assertThrows; - -import android.os.Parcel; -import android.os.SystemClock; -import android.platform.test.annotations.Presubmit; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@Presubmit -@RunWith(AndroidJUnit4.class) -public class VirtualSensorEventTest { - - private static final long TIMESTAMP_NANOS = SystemClock.elapsedRealtimeNanos(); - private static final float[] SENSOR_VALUES = new float[] {1.2f, 3.4f, 5.6f}; - - @Test - public void parcelAndUnparcel_matches() { - final VirtualSensorEvent originalEvent = new VirtualSensorEvent.Builder(SENSOR_VALUES) - .setTimestampNanos(TIMESTAMP_NANOS) - .build(); - final Parcel parcel = Parcel.obtain(); - originalEvent.writeToParcel(parcel, /* flags= */ 0); - parcel.setDataPosition(0); - final VirtualSensorEvent recreatedEvent = - VirtualSensorEvent.CREATOR.createFromParcel(parcel); - assertThat(recreatedEvent.getValues()).isEqualTo(originalEvent.getValues()); - assertThat(recreatedEvent.getTimestampNanos()).isEqualTo(originalEvent.getTimestampNanos()); - } - - @Test - public void sensorEvent_nullValues() { - assertThrows( - IllegalArgumentException.class, () -> new VirtualSensorEvent.Builder(null).build()); - } - - @Test - public void sensorEvent_noValues() { - assertThrows( - IllegalArgumentException.class, - () -> new VirtualSensorEvent.Builder(new float[0]).build()); - } - - @Test - public void sensorEvent_noTimestamp_usesCurrentTime() { - final VirtualSensorEvent event = new VirtualSensorEvent.Builder(SENSOR_VALUES).build(); - assertThat(event.getValues()).isEqualTo(SENSOR_VALUES); - assertThat(TIMESTAMP_NANOS).isLessThan(event.getTimestampNanos()); - assertThat(event.getTimestampNanos()).isLessThan(SystemClock.elapsedRealtimeNanos()); - } - - @Test - public void sensorEvent_created() { - final VirtualSensorEvent event = new VirtualSensorEvent.Builder(SENSOR_VALUES) - .setTimestampNanos(TIMESTAMP_NANOS) - .build(); - assertThat(event.getTimestampNanos()).isEqualTo(TIMESTAMP_NANOS); - assertThat(event.getValues()).isEqualTo(SENSOR_VALUES); - } -} diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt index ee1b2aa9a259..a0d8dcf830e8 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt @@ -28,6 +28,7 @@ import kotlin.math.ceil import kotlin.math.floor import org.junit.Test import org.junit.runner.RunWith +import kotlin.random.Random.Default.nextFloat @Presubmit @RunWith(AndroidJUnit4::class) @@ -124,17 +125,23 @@ class FontScaleConverterFactoryTest { @LargeTest @Test fun allFeasibleScalesAndConversionsDoNotCrash() { - generateSequenceOfFractions(-10f..10f, step = 0.01f) - .mapNotNull{ FontScaleConverterFactory.forScale(it) }!! + generateSequenceOfFractions(-10f..10f, step = 0.1f) + .fuzzFractions() + .mapNotNull{ FontScaleConverterFactory.forScale(it) } .flatMap{ table -> - generateSequenceOfFractions(-2000f..2000f, step = 0.01f) + generateSequenceOfFractions(-2000f..2000f, step = 0.1f) + .fuzzFractions() .map{ Pair(table, it) } } .forEach { (table, sp) -> try { - assertWithMessage("convertSpToDp(%s) on table: %s", sp, table) - .that(table.convertSpToDp(sp)) - .isFinite() + // Truth is slow because it creates a bunch of + // objects. Don't use it unless we need to. + if (!table.convertSpToDp(sp).isFinite()) { + assertWithMessage("convertSpToDp(%s) on table: %s", sp, table) + .that(table.convertSpToDp(sp)) + .isFinite() + } } catch (e: Exception) { throw AssertionError("Exception during convertSpToDp($sp) on table: $table", e) } @@ -168,6 +175,30 @@ class FontScaleConverterFactoryTest { assertThat(fractions).doesNotContain(-.35f) } + @Test + fun testFuzzFractions() { + val numFuzzedFractions = 6 + val fractions = generateSequenceOfFractions(-1000f..1000f, step = 0.1f) + .fuzzFractions() + .toList() + fractions.forEach { + assertThat(it).isAtLeast(-1000f) + assertThat(it).isLessThan(1001f) + } + + val numGeneratedFractions = 1000 * 2 * 10 + 1 // Don't forget the 0 in the middle! + assertThat(fractions).hasSize(numGeneratedFractions * numFuzzedFractions) + + assertThat(fractions).contains(100f) + assertThat(fractions).contains(500.1f) + assertThat(fractions).contains(500.2f) + assertThat(fractions).contains(0.2f) + assertThat(fractions).contains(0f) + assertThat(fractions).contains(-10f) + assertThat(fractions).contains(-10f) + assertThat(fractions).contains(-10.3f) + } + companion object { private const val CONVERSION_TOLERANCE = 0.05f } @@ -184,3 +215,9 @@ fun generateSequenceOfFractions( .takeWhile { it <= endInclusive } .map{ it.toFloat() / multiplier } } + +private fun Sequence<Float>.fuzzFractions(): Sequence<Float> { + return flatMap { i -> + listOf(i, i + 0.01f, i + 0.054f, i + 0.099f, i + nextFloat(), i + nextFloat()) + } +} diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java index 25664fb1d8d9..43334ab08b2f 100644 --- a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java +++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java @@ -101,8 +101,9 @@ public class CredentialManagerTest { mGetRequest = new GetCredentialRequest.Builder(Bundle.EMPTY).addCredentialOption( new CredentialOption(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY, Bundle.EMPTY, false)).build(); - mCreateRequest = new CreateCredentialRequest.Builder(Bundle.EMPTY, Bundle.EMPTY) - .setType(Credential.TYPE_PASSWORD_CREDENTIAL) + mCreateRequest = new CreateCredentialRequest.Builder( + Credential.TYPE_PASSWORD_CREDENTIAL, + Bundle.EMPTY, Bundle.EMPTY) .setIsSystemProviderRequired(false) .setAlwaysSendAppInfoToProvider(false) .build(); diff --git a/core/tests/coretests/src/android/provider/NameValueCacheTest.java b/core/tests/coretests/src/android/provider/NameValueCacheTest.java index b6fc137471a4..ccf8085f87ff 100644 --- a/core/tests/coretests/src/android/provider/NameValueCacheTest.java +++ b/core/tests/coretests/src/android/provider/NameValueCacheTest.java @@ -91,7 +91,7 @@ public class NameValueCacheTest { mConfigsCacheGenerationStore = new MemoryIntArray(2); mConfigsCacheGenerationStore.set(0, 123); mConfigsCacheGenerationStore.set(1, 456); - mSettingsCacheGenerationStore = new MemoryIntArray(2); + mSettingsCacheGenerationStore = new MemoryIntArray(3); mSettingsCacheGenerationStore.set(0, 234); mSettingsCacheGenerationStore.set(1, 567); mConfigsStorage = new HashMap<>(); @@ -163,6 +163,10 @@ public class NameValueCacheTest { Bundle incomingBundle = invocationOnMock.getArgument(4); String key = invocationOnMock.getArgument(3); String value = incomingBundle.getString(Settings.NameValueTable.VALUE); + boolean newSetting = false; + if (!mSettingsStorage.containsKey(key)) { + newSetting = true; + } mSettingsStorage.put(key, value); int currentGeneration; // Different settings have different generation codes @@ -173,12 +177,18 @@ public class NameValueCacheTest { currentGeneration = mSettingsCacheGenerationStore.get(1); mSettingsCacheGenerationStore.set(1, ++currentGeneration); } + if (newSetting) { + // Tracking the generation of all unset settings. + // Increment when a new setting is inserted + currentGeneration = mSettingsCacheGenerationStore.get(2); + mSettingsCacheGenerationStore.set(2, ++currentGeneration); + } return null; }); // Returns the value corresponding to a setting, or null if the setting - // doesn't have a value stored for it. Returns the generation key if the value isn't null - // and the caller asked for the generation key. + // doesn't have a value stored for it. Returns the generation key + // if the caller asked for the generation key. when(mMockIContentProvider.call(any(), eq(Settings.Secure.CONTENT_URI.getAuthority()), eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class))).thenAnswer( invocationOnMock -> { @@ -189,9 +199,15 @@ public class NameValueCacheTest { Bundle bundle = new Bundle(); bundle.putSerializable(Settings.NameValueTable.VALUE, value); - if (value != null && incomingBundle.containsKey( + if (incomingBundle.containsKey( Settings.CALL_METHOD_TRACK_GENERATION_KEY)) { - int index = key.equals(SETTING) ? 0 : 1; + int index; + if (value != null) { + index = key.equals(SETTING) ? 0 : 1; + } else { + // special index for unset settings + index = 2; + } bundle.putParcelable(Settings.CALL_METHOD_TRACK_GENERATION_KEY, mSettingsCacheGenerationStore); bundle.putInt(Settings.CALL_METHOD_GENERATION_INDEX_KEY, index); @@ -361,16 +377,38 @@ public class NameValueCacheTest { } @Test - public void testCaching_nullSetting() throws Exception { + public void testCaching_unsetSetting() throws Exception { String returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING); verify(mMockIContentProvider, times(1)).call(any(), any(), eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class)); assertThat(returnedValue).isNull(); String cachedValue = Settings.Secure.getString(mMockContentResolver, SETTING); - // Empty list won't be cached + // The first unset setting's generation number is cached + verifyNoMoreInteractions(mMockIContentProvider); + assertThat(cachedValue).isNull(); + + String returnedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING2); verify(mMockIContentProvider, times(2)).call(any(), any(), eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class)); - assertThat(cachedValue).isNull(); + assertThat(returnedValue2).isNull(); + + String cachedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING); + // The second unset setting's generation number is cached + verifyNoMoreInteractions(mMockIContentProvider); + assertThat(cachedValue2).isNull(); + + Settings.Secure.putString(mMockContentResolver, SETTING, "a"); + // The generation for unset settings should have changed + returnedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING2); + verify(mMockIContentProvider, times(3)).call(any(), any(), + eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class)); + assertThat(returnedValue2).isNull(); + + // The generation tracker for the first setting should have change because it's set now + returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING); + verify(mMockIContentProvider, times(4)).call(any(), any(), + eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class)); + assertThat(returnedValue).isEqualTo("a"); } } diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java index 6d635af20645..3d4918b1bd42 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java @@ -58,7 +58,7 @@ public class AccessibilityNodeInfoTest { // The number of flags held in boolean properties. Their values should also be double-checked // in the methods above. - private static final int NUM_BOOLEAN_PROPERTIES = 26; + private static final int NUM_BOOLEAN_PROPERTIES = 27; @Test public void testStandardActions_serializationFlagIsValid() { diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java index 9b9a84b79da3..35b3267ea301 100644 --- a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java @@ -156,4 +156,19 @@ public class ProcessStatsTest extends TestCase { eq(0), eq(APP_1_PROCESS_NAME)); } + + @SmallTest + public void testSafelyResetClearsProcessInUidState() throws Exception { + ProcessStats processStats = new ProcessStats(); + ProcessState processState = + processStats.getProcessStateLocked( + APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME); + processState.makeActive(); + UidState uidState = processStats.mUidStates.get(APP_1_UID); + assertTrue(uidState.isInUse()); + processState.makeInactive(); + uidState.resetSafely(NOW_MS); + processState.makeActive(); + assertFalse(uidState.isInUse()); + } } diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp index 0d3b15a41e8c..2b22344a4ef2 100644 --- a/core/tests/overlaytests/device/Android.bp +++ b/core/tests/overlaytests/device/Android.bp @@ -29,6 +29,7 @@ android_test { static_libs: [ "androidx.test.rules", "testng", + "compatibility-device-util-axt", ], test_suites: ["device-tests"], data: [ diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java index 8e4b9efafccd..fcf71ed39ef5 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java @@ -37,10 +37,12 @@ import android.view.View; import androidx.test.InstrumentationRegistry; +import com.android.compatibility.common.util.AmUtils; import com.android.internal.util.ArrayUtils; import com.android.overlaytest.view.TestTextView; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; @@ -70,6 +72,13 @@ public abstract class OverlayBaseTest { mMode = mode; } + @BeforeClass + public static void setUpClass() { + // Wait for package_added broadcasts to be handled so that OverlayManagerService + // can update it's internal state with the new packages. + AmUtils.waitForBroadcastBarrier(); + } + @Before public void setUp() { mContext = InstrumentationRegistry.getContext(); diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 3d81d37aff20..913eaf2391f6 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -271,6 +271,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", "at": "com\/android\/server\/wm\/AppTransition.java" }, + "-1868518158": { + "message": "Pending back animation due to another animation is running", + "level": "WARN", + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" + }, "-1868124841": { "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b", "level": "VERBOSE", @@ -1291,6 +1297,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-894942237": { + "message": "Force Playing Transition: %d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" + }, "-883738232": { "message": "Adding more than one toast window for UID at a time.", "level": "WARN", @@ -1549,6 +1561,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DragState.java" }, + "-692907078": { + "message": "Handling the deferred animation after transition finished", + "level": "DEBUG", + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" + }, "-677449371": { "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b", "level": "DEBUG", @@ -4231,12 +4249,6 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "1878927091": { - "message": "prepareSurface: No changes in animation for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, "1891501279": { "message": "cancelAnimation(): reason=%s", "level": "DEBUG", diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index a39dd0853ca6..8dd23b70ae61 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -2001,7 +2001,7 @@ public final class Bitmap implements Parcelable { checkPixelAccess(x, y); final ColorSpace cs = getColorSpace(); - if (cs.equals(ColorSpace.get(ColorSpace.Named.SRGB))) { + if (cs == null || cs.equals(ColorSpace.get(ColorSpace.Named.SRGB))) { return Color.valueOf(nativeGetPixel(mNativePtr, x, y)); } // The returned value is in kRGBA_F16_SkColorType, which is packed as diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java index a7c508c75ac9..feedb7d3e2bf 100644 --- a/graphics/java/android/graphics/Gainmap.java +++ b/graphics/java/android/graphics/Gainmap.java @@ -63,20 +63,20 @@ import libcore.util.NativeAllocationRegistry; * as follows: * * First, let W be a weight parameter determining how much the gainmap will be applied. - * W = clamp((log(H) - log(displayRatioHdr)) / - * (log(displayRatioHdr) - log(displayRatioSdr), 0, 1) + * W = clamp((log(H) - log(minDisplayRatioForHdrTransition)) / + * (log(displayRatioForFullHdr) - log(minDisplayRatioForHdrTransition), 0, 1) * * Next, let L be the gainmap value in log space. We compute this from the value G that was * sampled from the texture as follows: - * L = mix(log(gainmapRatioMin), log(gainmapRatioMax), pow(G, gainmapGamma)) + * L = mix(log(ratioMin), log(ratioMax), pow(G, gamma)) * * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then * compute: * D = (B + epsilonSdr) * exp(L * W) - epsilonHdr - * If the base image is HDR then compute: - * D = (B + epsilonHdr) * exp(L * (W - 1)) - epsilonSdr * - * In the above math, log() is a natural logarithm and exp() is natural exponentiation. + * In the above math, log() is a natural logarithm and exp() is natural exponentiation. The base + * for these functions cancels out and does not affect the result, so other bases may be used + * if preferred. */ public final class Gainmap implements Parcelable { diff --git a/graphics/java/android/graphics/text/GraphemeBreak.java b/graphics/java/android/graphics/text/GraphemeBreak.java new file mode 100644 index 000000000000..f82b2fd659cc --- /dev/null +++ b/graphics/java/android/graphics/text/GraphemeBreak.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.text; + +/** @hide */ +public class GraphemeBreak { + private GraphemeBreak() { } + + /** + * Util method that checks if the offsets in given range are grapheme break. + * + * @param advances the advances of characters in the given text. It contains the font + * information used by the algorithm to determine the grapheme break. It's useful + * when some character is missing in the font. For example, if the smile emoji + * "0xD83D 0xDE0A" is not found in the font and is displayed as 2 characters. + * We can't treat it as a single grapheme cluster. + * @param text the text to be processed. + * @param start the start offset of the queried range, inclusive. + * @param end the end offset of the queried range, exclusive. + * @param isGraphemeBreak the array to receive the result. The i-th element of the + * array will be set to true if the offset (start + i) is a grapheme + * break; otherwise, it will be set to false. + */ + public static void isGraphemeBreak(float[] advances, char[] text, int start, int end, + boolean[] isGraphemeBreak) { + if (start > end) { + throw new IllegalArgumentException("start is greater than end: start = " + start + + " end = " + end); + } + if (advances.length < end) { + throw new IllegalArgumentException("the length of advances is less than end" + + "advances.length = " + advances.length + + " end = " + end); + } + if (isGraphemeBreak.length < end - start) { + throw new IndexOutOfBoundsException("isGraphemeBreak doesn't have enough space to " + + "receive the result, isGraphemeBreak.length: " + isGraphemeBreak.length + + " needed space: " + (end - start)); + } + nIsGraphemeBreak(advances, text, start, end, isGraphemeBreak); + } + + private static native void nIsGraphemeBreak(float[] advances, char[] text, int start, int end, + boolean[] isGraphemeBreak); +} diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java index 67eb117cb17c..babcfc3815f4 100644 --- a/graphics/java/android/graphics/text/LineBreaker.java +++ b/graphics/java/android/graphics/text/LineBreaker.java @@ -22,7 +22,6 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; -import android.os.Trace; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; @@ -476,26 +475,19 @@ public class LineBreaker { @NonNull MeasuredText measuredPara, @NonNull ParagraphConstraints constraints, @IntRange(from = 0) int lineNumber) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "compute line break"); - long result = 0; - try { - result = nComputeLineBreaks( - mNativePtr, - - // Inputs - measuredPara.getChars(), - measuredPara.getNativePtr(), - measuredPara.getChars().length, - constraints.mFirstWidth, - constraints.mFirstWidthLineCount, - constraints.mWidth, - constraints.mVariableTabStops, - constraints.mDefaultTabStop, - lineNumber); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - return new Result(result); + return new Result(nComputeLineBreaks( + mNativePtr, + + // Inputs + measuredPara.getChars(), + measuredPara.getNativePtr(), + measuredPara.getChars().length, + constraints.mFirstWidth, + constraints.mFirstWidthLineCount, + constraints.mWidth, + constraints.mVariableTabStops, + constraints.mDefaultTabStop, + lineNumber)); } @FastNative diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 9f3c19b2b545..caefb2e9516c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -752,8 +752,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @GuardedBy("mLock") void onActivityCreated(@NonNull WindowContainerTransaction wct, @NonNull Activity launchedActivity) { - // TODO(b/229680885): we don't support launching into primary yet because we want to always - // launch the new activity on top. resolveActivityToContainer(wct, launchedActivity, false /* isOnReparent */); updateCallbackIfNecessary(); } @@ -789,6 +787,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return true; } + final TaskFragmentContainer container = getContainerWithActivity(activity); + if (!isOnReparent && container != null + && container.getTaskContainer().getTopTaskFragmentContainer() != container) { + // Do not resolve if the launched activity is not the top-most container in the Task. + return true; + } + /* * We will check the following to see if there is any embedding rule matched: * 1. Whether the new launched activity should always expand. @@ -811,6 +816,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return true; } + // Skip resolving the following split-rules if the launched activity has been requested + // to be launched into its current container. + if (container != null && container.isActivityInRequestedTaskFragment( + activity.getActivityToken())) { + return true; + } + // 3. Whether the new launched activity has already been in a split with a rule matched. if (isNewActivityInSplitWithRuleMatched(activity)) { return true; @@ -2066,6 +2078,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (!container.hasActivity(activityToken) && container.getTaskFragmentToken() .equals(initialTaskFragmentToken)) { + if (ActivityClient.getInstance().isRequestedToLaunchInTaskFragment( + activityToken, initialTaskFragmentToken)) { + container.addPendingAppearedInRequestedTaskFragmentActivity( + activity); + } + // The onTaskFragmentInfoChanged callback containing this activity has // not reached the client yet, so add the activity to the pending // appeared activities. @@ -2157,6 +2175,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // TODO(b/232042367): Consolidate the activity create handling so that we can handle // cross-process the same as normal. + // Early return if the launching taskfragment is already been set. + if (options.getBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN) != null) { + synchronized (mLock) { + mCurrentIntent = intent; + } + return super.onStartActivity(who, intent, options); + } + final Activity launchingActivity; if (who instanceof Activity) { // We will check if the new activity should be split with the activity that launched diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index b38f8245a2aa..6c553a836dbd 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -86,6 +86,12 @@ class TaskFragmentContainer { @Nullable private Intent mPendingAppearedIntent; + /** + * The activities that were explicitly requested to be launched in its current TaskFragment, + * but haven't been added to {@link #mInfo} yet. + */ + final ArrayList<IBinder> mPendingAppearedInRequestedTaskFragmentActivities = new ArrayList<>(); + /** Containers that are dependent on this one and should be completely destroyed on exit. */ private final List<TaskFragmentContainer> mContainersToFinishOnExit = new ArrayList<>(); @@ -296,6 +302,8 @@ class TaskFragmentContainer { void removePendingAppearedActivity(@NonNull IBinder activityToken) { mPendingAppearedActivities.remove(activityToken); + // Also remove the activity from the mPendingInRequestedTaskFragmentActivities. + mPendingAppearedInRequestedTaskFragmentActivities.remove(activityToken); } @GuardedBy("mController.mLock") @@ -424,7 +432,7 @@ class TaskFragmentContainer { for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) { final IBinder activityToken = mPendingAppearedActivities.get(i); if (infoActivities.contains(activityToken)) { - mPendingAppearedActivities.remove(i); + removePendingAppearedActivity(activityToken); } } } @@ -720,6 +728,29 @@ class TaskFragmentContainer { mLastCompanionTaskFragment = fragmentToken; } + /** + * Adds the pending appeared activity that has requested to be launched in this task fragment. + * @see android.app.ActivityClient#isRequestedToLaunchInTaskFragment + */ + void addPendingAppearedInRequestedTaskFragmentActivity(Activity activity) { + final IBinder activityToken = activity.getActivityToken(); + if (hasActivity(activityToken)) { + return; + } + mPendingAppearedInRequestedTaskFragmentActivities.add(activity.getActivityToken()); + } + + /** + * Checks if the given activity has requested to be launched in this task fragment. + * @see #addPendingAppearedInRequestedTaskFragmentActivity + */ + boolean isActivityInRequestedTaskFragment(IBinder activityToken) { + if (mInfo != null && mInfo.getActivitiesRequestedInTaskFragment().contains(activityToken)) { + return true; + } + return mPendingAppearedInRequestedTaskFragmentActivities.contains(activityToken); + } + /** Gets the parent leaf Task id. */ int getTaskId() { return mTaskContainer.getTaskId(); diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java index 459ec9f89c4a..a069ac7256d6 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java @@ -177,6 +177,7 @@ public class EmbeddingTestUtils { 1, isVisible, Collections.singletonList(activity.getActivityToken()), + new ArrayList<>(), new Point(), false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java index bbb454d31c38..dd087e8eb7c9 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java @@ -124,7 +124,7 @@ public class JetpackTaskFragmentOrganizerTest { private TaskFragmentInfo createMockInfo(TaskFragmentContainer container) { return new TaskFragmentInfo(container.getTaskFragmentToken(), mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */, - false /* isVisible */, new ArrayList<>(), new Point(), + false /* isVisible */, new ArrayList<>(), new ArrayList<>(), new Point(), false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, false /* isClearedForReorderActivityToFront */, new Point()); } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java index 61cd7485ff1d..3d0e1c8cf788 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java @@ -700,7 +700,7 @@ public class SplitControllerTest { final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); - assertFalse(result); + assertTrue(result); verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(), any(), anyBoolean()); } @@ -734,7 +734,7 @@ public class SplitControllerTest { final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); - assertFalse(result); + assertTrue(result); verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(), any(), anyBoolean()); } @@ -808,7 +808,7 @@ public class SplitControllerTest { final Activity launchedActivity = createMockActivity(); primaryContainer.addPendingAppearedActivity(launchedActivity); - assertFalse(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity, + assertTrue(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity, false /* isOnReparent */)); } @@ -944,7 +944,7 @@ public class SplitControllerTest { boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); - assertFalse(result); + assertTrue(result); assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity)); diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml index 049980803ee3..9473cdd607d6 100644 --- a/libs/WindowManager/Shell/res/color/split_divider_background.xml +++ b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2021 The Android Open Source Project + ~ 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. @@ -14,6 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> +<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@android:color/system_neutral1_500" android:lStar="15" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml index b3d260299106..0e165fca4fd3 100644 --- a/libs/WindowManager/Shell/res/color/taskbar_background.xml +++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml @@ -16,5 +16,5 @@ --> <!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_500" android:lStar="15" /> + <item android:color="@android:color/system_neutral1_500" android:lStar="95" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml index 9167382d0898..c6e634c6622c 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml @@ -17,6 +17,6 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/white" /> - <corners android:radius="20dp" /> + <corners android:radius="@dimen/caption_menu_corner_radius" /> <stroke android:width="1dp" android:color="#b3b3b3"/> </shape> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml index f6e3f2edfa14..f9aeb6a8448a 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml @@ -21,7 +21,6 @@ android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/desktop_mode_decor_menu_background" - android:elevation="@dimen/caption_menu_elevation" android:divider="?android:attr/dividerHorizontal" android:showDividers="middle" android:dividerPadding="18dip"> @@ -63,38 +62,46 @@ android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="0.5" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/fullscreen_button" android:contentDescription="@string/fullscreen_text" - android:background="@drawable/caption_fullscreen_button"/> + android:src="@drawable/caption_fullscreen_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/split_screen_button" android:contentDescription="@string/split_screen_text" - android:background="@drawable/caption_split_screen_button"/> + android:src="@drawable/caption_split_screen_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/floating_button" android:contentDescription="@string/float_button_text" - android:background="@drawable/caption_floating_button"/> + android:src="@drawable/caption_floating_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/desktop_button" android:contentDescription="@string/desktop_text" - android:background="@drawable/caption_desktop_button"/> + android:src="@drawable/caption_desktop_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml index e8edad15dfc3..413cfd78fd91 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml @@ -16,9 +16,7 @@ <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@android:color/system_neutral1_900"> + style="@style/LetterboxDialog"> <!-- The background of the top-level layout acts as the background dim. --> diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml index ba9852c4dd6b..5aff4159e135 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml @@ -16,14 +16,10 @@ <com.android.wm.shell.compatui.RestartDialogLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@android:color/system_neutral1_900"> + style="@style/LetterboxDialog"> <!-- The background of the top-level layout acts as the background dim. --> - <!--TODO (b/266288912): Resolve overdraw warning --> - <!-- Vertical margin will be set dynamically since it depends on task bounds. Setting the alpha of the dialog container to 0, since it shouldn't be visible until the enter animation starts. --> diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml index 83c4d93982f4..5c6bb57a7f1c 100644 --- a/libs/WindowManager/Shell/res/values-night/colors.xml +++ b/libs/WindowManager/Shell/res/values-night/colors.xml @@ -15,6 +15,7 @@ --> <resources> + <color name="docked_divider_handle">#ffffff</color> <!-- Bubbles --> <color name="bubbles_icon_tint">@color/GM2_grey_200</color> <!-- Splash screen--> diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 6e750a3d5e34..6fb70006e67f 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -17,7 +17,8 @@ */ --> <resources> - <color name="docked_divider_handle">#ffffff</color> + <color name="docked_divider_handle">#000000</color> + <color name="split_divider_background">@color/taskbar_background</color> <drawable name="forced_resizable_background">#59000000</drawable> <color name="minimize_dock_shadow_start">#60000000</color> <color name="minimize_dock_shadow_end">#00000000</color> @@ -41,6 +42,9 @@ <color name="letterbox_education_accent_primary">@android:color/system_accent1_100</color> <color name="letterbox_education_text_secondary">@android:color/system_neutral2_200</color> + <!-- Letterbox Dialog --> + <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color> + <!-- GM2 colors --> <color name="GM2_grey_200">#E8EAED</color> <color name="GM2_grey_700">#5F6368</color> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 336c156e831a..680ad5101366 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -370,6 +370,10 @@ <dimen name="freeform_resize_corner">44dp</dimen> - <dimen name="caption_menu_elevation">4dp</dimen> + <!-- The radius of the caption menu shadow. --> + <dimen name="caption_menu_shadow_radius">4dp</dimen> + + <!-- The radius of the caption menu corners. --> + <dimen name="caption_menu_corner_radius">20dp</dimen> </resources> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index 0a0c49f2d93f..bc2e71d1c013 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -38,11 +38,9 @@ </style> <style name="CaptionWindowingButtonStyle"> - <item name="android:layout_width">32dp</item> - <item name="android:layout_height">32dp</item> + <item name="android:layout_width">40dp</item> + <item name="android:layout_height">40dp</item> <item name="android:padding">4dp</item> - <item name="android:layout_marginTop">5dp</item> - <item name="android:layout_marginBottom">5dp</item> </style> <style name="CaptionMenuButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> @@ -80,6 +78,12 @@ <item name="android:textColor">@color/tv_pip_edu_text</item> </style> + <style name="LetterboxDialog" parent="@android:style/Theme.Holo"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:background">@color/letterbox_dialog_background</item> + </style> + <style name="RestartDialogTitleText"> <item name="android:textSize">24sp</item> <item name="android:textColor">?android:attr/textColorPrimary</item> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index b3fff1d05263..0b8759890359 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -552,6 +552,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont if (runner.isWaitingAnimation()) { ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Gesture released, but animation didn't ready."); return; + } else if (runner.isAnimationCancelled()) { + invokeOrCancelBack(); + return; } startPostCommitAnimation(); } @@ -653,7 +656,19 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } @Override - public void onAnimationCancelled() { } + public void onAnimationCancelled() { + mShellExecutor.execute(() -> { + final BackAnimationRunner runner = mAnimationDefinition.get( + mBackNavigationInfo.getType()); + if (runner == null) { + return; + } + runner.cancelAnimation(); + if (!mBackGestureStarted) { + invokeOrCancelBack(); + } + }); + } }; mBackAnimationAdapter = new BackAnimationAdapter(runner); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java index d70b8f53a911..82c523f337db 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java @@ -41,6 +41,9 @@ class BackAnimationRunner { // Whether we are waiting to receive onAnimationStart private boolean mWaitingAnimation; + /** True when the back animation is cancelled */ + private boolean mAnimationCancelled; + BackAnimationRunner(@NonNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner) { mCallback = callback; @@ -81,9 +84,19 @@ class BackAnimationRunner { void startGesture() { mWaitingAnimation = true; + mAnimationCancelled = false; } boolean isWaitingAnimation() { return mWaitingAnimation; } + + void cancelAnimation() { + mWaitingAnimation = false; + mAnimationCancelled = true; + } + + boolean isAnimationCancelled() { + return mAnimationCancelled; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 36c0cb6dfe19..852fae695046 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -61,6 +61,7 @@ import android.os.Binder; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.service.notification.NotificationListenerService; @@ -129,6 +130,15 @@ public class BubbleController implements ConfigurationChangeListener { private static final String SYSTEM_DIALOG_REASON_KEY = "reason"; private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav"; + // TODO(b/256873975) Should use proper flag when available to shell/launcher + /** + * Whether bubbles are showing in the bubble bar from launcher. This is only available + * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used + * to check all conditions that indicate if the bubble bar is in use. + */ + private static final boolean BUBBLE_BAR_ENABLED = + SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false); + private final Context mContext; private final BubblesImpl mImpl = new BubblesImpl(); private Bubbles.BubbleExpandListener mExpandListener; @@ -155,9 +165,6 @@ public class BubbleController implements ConfigurationChangeListener { private final ShellExecutor mBackgroundExecutor; - // Whether or not we should show bubbles pinned at the bottom of the screen. - private boolean mIsBubbleBarEnabled; - private BubbleLogger mLogger; private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; @@ -540,10 +547,10 @@ public class BubbleController implements ConfigurationChangeListener { mDataRepository.removeBubblesForUser(removedUserId, parentUserId); } - // TODO(b/256873975): Should pass this into the constructor once flags are available to shell. - /** Sets whether the bubble bar is enabled (i.e. bubbles pinned to bottom on large screens). */ - public void setBubbleBarEnabled(boolean enabled) { - mIsBubbleBarEnabled = enabled; + /** Whether bubbles are showing in the bubble bar. */ + public boolean isShowingAsBubbleBar() { + // TODO(b/269670598): should also check that we're in gesture nav + return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen(); } /** Whether this userId belongs to the current user. */ @@ -612,12 +619,6 @@ public class BubbleController implements ConfigurationChangeListener { mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation); } - if (mIsBubbleBarEnabled && mBubblePositioner.isLargeScreen()) { - mBubblePositioner.setUsePinnedLocation(true); - } else { - mBubblePositioner.setUsePinnedLocation(false); - } - addToWindowManagerMaybe(); } @@ -1918,13 +1919,6 @@ public class BubbleController implements ConfigurationChangeListener { } @Override - public void setBubbleBarEnabled(boolean enabled) { - mMainExecutor.execute(() -> { - BubbleController.this.setBubbleBarEnabled(enabled); - }); - } - - @Override public void onNotificationPanelExpandedChanged(boolean expanded) { mMainExecutor.execute( () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 6230d22ebe12..3fd09675a245 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -283,7 +283,7 @@ public class BubbleData { } boolean isShowingOverflow() { - return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar()); + return mShowingOverflow && isExpanded(); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 57c7731e69ed..ecddbda0fff4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -16,6 +16,7 @@ package com.android.wm.shell.bubbles; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; @@ -226,6 +227,8 @@ public class BubbleExpandedView extends LinearLayout { try { options.setTaskAlwaysOnTop(true); options.setLaunchedFromBubble(true); + options.setPendingIntentBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_ALLOWED); Intent fillInIntent = new Intent(); // Apply flags to make behaviour match documentLaunchMode=always. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 07c58527a815..5ea2450114f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -18,9 +18,6 @@ package com.android.wm.shell.bubbles; import static android.view.View.LAYOUT_DIRECTION_RTL; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.annotation.IntDef; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -39,8 +36,6 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.icons.IconNormalizer; import com.android.wm.shell.R; -import java.lang.annotation.Retention; - /** * Keeps track of display size, configuration, and specific bubble sizes. One place for all * placement and positioning calculations to refer to. @@ -50,15 +45,6 @@ public class BubblePositioner { ? "BubblePositioner" : BubbleDebugConfig.TAG_BUBBLES; - @Retention(SOURCE) - @IntDef({TASKBAR_POSITION_NONE, TASKBAR_POSITION_RIGHT, TASKBAR_POSITION_LEFT, - TASKBAR_POSITION_BOTTOM}) - @interface TaskbarPosition {} - public static final int TASKBAR_POSITION_NONE = -1; - public static final int TASKBAR_POSITION_RIGHT = 0; - public static final int TASKBAR_POSITION_LEFT = 1; - public static final int TASKBAR_POSITION_BOTTOM = 2; - /** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/ public static final int NUM_VISIBLE_WHEN_RESTING = 2; /** Indicates a bubble's height should be the maximum available space. **/ @@ -108,15 +94,9 @@ public class BubblePositioner { private int mOverflowHeight; private int mMinimumFlyoutWidthLargeScreen; - private PointF mPinLocation; private PointF mRestingStackPosition; private int[] mPaddings = new int[4]; - private boolean mShowingInTaskbar; - private @TaskbarPosition int mTaskbarPosition = TASKBAR_POSITION_NONE; - private int mTaskbarIconSize; - private int mTaskbarSize; - public BubblePositioner(Context context, WindowManager windowManager) { mContext = context; mWindowManager = windowManager; @@ -153,27 +133,11 @@ public class BubblePositioner { + " insets: " + insets + " isLargeScreen: " + mIsLargeScreen + " isSmallTablet: " + mIsSmallTablet - + " bounds: " + bounds - + " showingInTaskbar: " + mShowingInTaskbar); + + " bounds: " + bounds); } updateInternal(mRotation, insets, bounds); } - /** - * Updates position information to account for taskbar state. - * - * @param taskbarPosition which position the taskbar is displayed in. - * @param showingInTaskbar whether the taskbar is being shown. - */ - public void updateForTaskbar(int iconSize, - @TaskbarPosition int taskbarPosition, boolean showingInTaskbar, int taskbarSize) { - mShowingInTaskbar = showingInTaskbar; - mTaskbarIconSize = iconSize; - mTaskbarPosition = taskbarPosition; - mTaskbarSize = taskbarSize; - update(); - } - @VisibleForTesting public void updateInternal(int rotation, Insets insets, Rect bounds) { mRotation = rotation; @@ -232,10 +196,6 @@ public class BubblePositioner { R.dimen.bubbles_flyout_min_width_large_screen); mMaxBubbles = calculateMaxBubbles(); - - if (mShowingInTaskbar) { - adjustForTaskbar(); - } } /** @@ -260,30 +220,6 @@ public class BubblePositioner { return mDefaultMaxBubbles; } - /** - * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should - * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space - * and insets to account for the taskbar. - */ - // TODO(b/171559950): When the insets are reported correctly we can remove this logic - private void adjustForTaskbar() { - // When bar is showing on edges... subtract that inset because we appear on top - if (mShowingInTaskbar && mTaskbarPosition != TASKBAR_POSITION_BOTTOM) { - WindowInsets metricInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets(); - Insets navBarInsets = metricInsets.getInsetsIgnoringVisibility( - WindowInsets.Type.navigationBars()); - int newInsetLeft = mInsets.left; - int newInsetRight = mInsets.right; - if (mTaskbarPosition == TASKBAR_POSITION_LEFT) { - mPositionRect.left -= navBarInsets.left; - newInsetLeft -= navBarInsets.left; - } else if (mTaskbarPosition == TASKBAR_POSITION_RIGHT) { - mPositionRect.right += navBarInsets.right; - newInsetRight -= navBarInsets.right; - } - mInsets = Insets.of(newInsetLeft, mInsets.top, newInsetRight, mInsets.bottom); - } - } /** * @return a rect of available screen space accounting for orientation, system bars and cutouts. @@ -327,14 +263,12 @@ public class BubblePositioner { * to the left or right side. */ public boolean showBubblesVertically() { - return isLandscape() || mShowingInTaskbar || mIsLargeScreen; + return isLandscape() || mIsLargeScreen; } /** Size of the bubble. */ public int getBubbleSize() { - return (mShowingInTaskbar && mTaskbarIconSize > 0) - ? mTaskbarIconSize - : mBubbleSize; + return mBubbleSize; } /** The amount of padding at the top of the screen that the bubbles avoid when being placed. */ @@ -699,9 +633,6 @@ public class BubblePositioner { /** The position the bubble stack should rest at when collapsed. */ public PointF getRestingPosition() { - if (mPinLocation != null) { - return mPinLocation; - } if (mRestingStackPosition == null) { return getDefaultStartPosition(); } @@ -713,9 +644,6 @@ public class BubblePositioner { * is being shown. */ public PointF getDefaultStartPosition() { - if (mPinLocation != null) { - return mPinLocation; - } // Start on the left if we're in LTR, right otherwise. final boolean startOnLeft = mContext.getResources().getConfiguration().getLayoutDirection() @@ -730,7 +658,6 @@ public class BubblePositioner { 1 /* default starts with 1 bubble */)); } - /** * Returns the region that the stack position must stay within. This goes slightly off the left * and right sides of the screen, below the status bar/cutout and above the navigation bar. @@ -751,39 +678,6 @@ public class BubblePositioner { } /** - * @return whether the bubble stack is pinned to the taskbar. - */ - public boolean showingInTaskbar() { - return mShowingInTaskbar; - } - - /** - * @return the taskbar position if set. - */ - public int getTaskbarPosition() { - return mTaskbarPosition; - } - - public int getTaskbarSize() { - return mTaskbarSize; - } - - /** - * In some situations bubbles will be pinned to a specific onscreen location. This sets whether - * bubbles should be pinned or not. - */ - public void setUsePinnedLocation(boolean usePinnedLocation) { - if (usePinnedLocation) { - mShowingInTaskbar = true; - mPinLocation = new PointF(mPositionRect.right - mBubbleSize, - mPositionRect.bottom - mBubbleSize); - } else { - mPinLocation = null; - mShowingInTaskbar = false; - } - } - - /** * Navigation bar has an area where system gestures can be started from. * * @return {@link Rect} for system navigation bar gesture zone diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index abe42eec7061..7d71089ef4fa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -680,8 +680,6 @@ public class BubbleStackView extends FrameLayout // Re-show the expanded view if we hid it. showExpandedViewIfNeeded(); - } else if (mPositioner.showingInTaskbar()) { - mStackAnimationController.snapStackBack(); } else { // Fling the stack to the edge, and save whether or not it's going to end up on // the left side of the screen. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java index 1753cda895fe..4c0a93fb9355 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java @@ -273,11 +273,6 @@ public interface Bubbles { */ void onUserRemoved(int removedUserId); - /** - * Sets whether bubble bar should be enabled or not. - */ - void setBubbleBarEnabled(boolean enabled); - /** Listener to find out about stack expansion / collapse events. */ interface BubbleExpandListener { /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java index 0ee0ea60a1bc..5533842f2d89 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java @@ -417,23 +417,9 @@ public class StackAnimationController extends } /** - * Snaps the stack back to the previous resting position. - */ - public void snapStackBack() { - if (mLayout == null) { - return; - } - PointF p = getStackPositionAlongNearestHorizontalEdge(); - springStackAfterFling(p.x, p.y); - } - - /** * Where the stack would be if it were snapped to the nearest horizontal edge (left or right). */ public PointF getStackPositionAlongNearestHorizontalEdge() { - if (mPositioner.showingInTaskbar()) { - return mPositioner.getRestingPosition(); - } final PointF stackPos = getStackPosition(); final boolean onLeft = mLayout.isFirstChildXLeftOfCenter(stackPos.x); final RectF bounds = mPositioner.getAllowableStackPositionRegion(getBubbleCount()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 7ac4d51c1502..b447a543989e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -120,6 +120,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private int mOrientation; private int mRotation; private int mDensity; + private int mUiMode; private final boolean mDimNonImeSide; private ValueAnimator mDividerFlingAnimator; @@ -295,10 +296,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final Rect rootBounds = configuration.windowConfiguration.getBounds(); final int orientation = configuration.orientation; final int density = configuration.densityDpi; + final int uiMode = configuration.uiMode; if (mOrientation == orientation && mRotation == rotation && mDensity == density + && mUiMode == uiMode && mRootBounds.equals(rootBounds)) { return false; } @@ -310,6 +313,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mRootBounds.set(rootBounds); mRotation = rotation; mDensity = density; + mUiMode = uiMode; mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null); updateDividerConfig(mContext); initDividerPosition(mTempRect); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index 8895fcab0c3d..73123b153382 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -25,16 +25,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Insets; -import android.graphics.Matrix; import android.graphics.Rect; -import android.graphics.RectF; import android.os.Handler; import android.view.LayoutInflater; import android.view.SurfaceControl; -import android.view.SyncRtSurfaceTransactionApplier; import android.view.View; import android.view.ViewRootImpl; import android.view.WindowManagerGlobal; +import android.window.SurfaceSyncGroup; import androidx.annotation.Nullable; @@ -71,12 +69,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis // exiting the move menu instead of showing the regular button menu. private boolean mCloseAfterExitMoveMenu; - private SyncRtSurfaceTransactionApplier mApplier; - private SyncRtSurfaceTransactionApplier mBackgroundApplier; - RectF mTmpSourceRectF = new RectF(); - RectF mTmpDestinationRectF = new RectF(); - Matrix mMoveTransform = new Matrix(); - public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState, SystemWindows systemWindows, Handler mainHandler) { mContext = context; @@ -324,44 +316,36 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis */ @Override public void resizePipMenu(@Nullable SurfaceControl pipLeash, - @Nullable SurfaceControl.Transaction t, - Rect destinationBounds) { + @Nullable SurfaceControl.Transaction pipTx, + Rect pipBounds) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString()); - if (destinationBounds.isEmpty()) { + "%s: resizePipMenu: %s", TAG, pipBounds.toShortString()); + if (pipBounds.isEmpty()) { return; } - if (!maybeCreateSyncApplier()) { + if (!isMenuReadyToMove()) { return; } - final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds); final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView); - final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams = - new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface) - .withWindowCrop(menuBounds) - .build(); - final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView); - final SyncRtSurfaceTransactionApplier.SurfaceParams backParams = - new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface) - .withWindowCrop(menuBounds) - .build(); - - // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the - // animations of the pip surface with the content of the front and back menu surfaces - mBackgroundApplier.scheduleApply(backParams); - if (pipLeash != null && t != null) { - final SyncRtSurfaceTransactionApplier.SurfaceParams - pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash) - .withMergeTransaction(t) - .build(); - mApplier.scheduleApply(frontParams, pipParams); - } else { - mApplier.scheduleApply(frontParams); + final Rect menuBounds = calculateMenuSurfaceBounds(pipBounds); + if (pipTx == null) { + pipTx = new SurfaceControl.Transaction(); } + pipTx.setWindowCrop(frontSurface, menuBounds.width(), menuBounds.height()); + pipTx.setWindowCrop(backSurface, menuBounds.width(), menuBounds.height()); + + // Synchronize drawing the content in the front and back surfaces together with the pip + // transaction and the window crop for the front and back surfaces + final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip"); + syncGroup.add(mPipMenuView.getRootSurfaceControl(), null); + syncGroup.add(mPipBackgroundView.getRootSurfaceControl(), null); + updateMenuBounds(pipBounds); + syncGroup.addTransaction(pipTx); + syncGroup.markSyncReady(); } private SurfaceControl getSurfaceControl(View v) { @@ -369,102 +353,66 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } @Override - public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction, - Rect pipDestBounds) { + public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction pipTx, + Rect pipBounds) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString()); + "%s: movePipMenu: %s", TAG, pipBounds.toShortString()); - if (pipDestBounds.isEmpty()) { - if (transaction == null) { + if (pipBounds.isEmpty()) { + if (pipTx == null) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: no transaction given", TAG); } return; } - if (!maybeCreateSyncApplier()) { + if (!isMenuReadyToMove()) { return; } - final Rect menuDestBounds = calculateMenuSurfaceBounds(pipDestBounds); - final Rect tmpSourceBounds = new Rect(); - // If there is no pip leash supplied, that means the PiP leash is already finalized - // resizing and the PiP menu is also resized. We then want to do a scale from the current - // new menu bounds. - if (pipLeash != null && transaction != null) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: tmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG); - mPipMenuView.getBoundsOnScreen(tmpSourceBounds); - } else { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: tmpSourceBounds based on menu width and height", TAG); - tmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height()); - } - - mTmpSourceRectF.set(tmpSourceBounds); - mTmpDestinationRectF.set(menuDestBounds); - mMoveTransform.setTranslate(mTmpDestinationRectF.left, mTmpDestinationRectF.top); - final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView); - final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams = - new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface) - .withMatrix(mMoveTransform) - .build(); - final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView); - final SyncRtSurfaceTransactionApplier.SurfaceParams backParams = - new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface) - .withMatrix(mMoveTransform) - .build(); - - // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the - // animations of the pip surface with the content of the front and back menu surfaces - mBackgroundApplier.scheduleApply(backParams); - if (pipLeash != null && transaction != null) { - final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams = - new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash) - .withMergeTransaction(transaction) - .build(); - mApplier.scheduleApply(frontParams, pipParams); - } else { - mApplier.scheduleApply(frontParams); - } - - updateMenuBounds(pipDestBounds); - } - - private boolean maybeCreateSyncApplier() { - if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) { + final Rect menuDestBounds = calculateMenuSurfaceBounds(pipBounds); + if (pipTx == null) { + pipTx = new SurfaceControl.Transaction(); + } + pipTx.setPosition(frontSurface, menuDestBounds.left, menuDestBounds.top); + pipTx.setPosition(backSurface, menuDestBounds.left, menuDestBounds.top); + + // Synchronize drawing the content in the front and back surfaces together with the pip + // transaction and the position change for the front and back surfaces + final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip"); + syncGroup.add(mPipMenuView.getRootSurfaceControl(), null); + syncGroup.add(mPipBackgroundView.getRootSurfaceControl(), null); + updateMenuBounds(pipBounds); + syncGroup.addTransaction(pipTx); + syncGroup.markSyncReady(); + } + + private boolean isMenuReadyToMove() { + final boolean ready = mPipMenuView != null && mPipMenuView.getViewRootImpl() != null + && mPipBackgroundView != null && mPipBackgroundView.getViewRootImpl() != null; + if (!ready) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Not going to move PiP, either menu or its parent is not created.", TAG); - return false; } - - if (mApplier == null) { - mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView); - } - if (mBackgroundApplier == null) { - mBackgroundApplier = new SyncRtSurfaceTransactionApplier(mPipBackgroundView); - } - return true; + return ready; } private void detachPipMenu() { if (mPipMenuView != null) { - mApplier = null; mSystemWindows.removeView(mPipMenuView); mPipMenuView = null; } if (mPipBackgroundView != null) { - mBackgroundApplier = null; mSystemWindows.removeView(mPipBackgroundView); mPipBackgroundView = null; } } @Override - public void updateMenuBounds(Rect destinationBounds) { - final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds); + public void updateMenuBounds(Rect pipBounds) { + final Rect menuBounds = calculateMenuSurfaceBounds(pipBounds); ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString()); mSystemWindows.updateViewLayout(mPipBackgroundView, @@ -473,9 +421,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height())); - if (mPipMenuView != null) { - mPipMenuView.updateBounds(destinationBounds); + mPipMenuView.updateBounds(pipBounds); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 427d79e3a1b9..70d3b3509b2f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -20,7 +20,6 @@ import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED; import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -205,7 +204,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // and exit, since exit itself can trigger a number of changes that update the stages. private boolean mShouldUpdateRecents; private boolean mExitSplitScreenOnHide; - private boolean mIsSplitEntering; + private boolean mIsDividerRemoteAnimating; private boolean mIsDropEntering; private boolean mIsExiting; @@ -661,6 +660,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + prepareEvictChildTasksIfSplitActive(wct); setSideStagePosition(splitPosition, wct); options1 = options1 != null ? options1 : new Bundle(); addActivityOptions(options1, mSideStage); @@ -675,6 +675,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + prepareEvictChildTasksIfSplitActive(wct); setSideStagePosition(splitPosition, wct); options1 = options1 != null ? options1 : new Bundle(); addActivityOptions(options1, mSideStage); @@ -688,6 +689,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + prepareEvictChildTasksIfSplitActive(wct); setSideStagePosition(splitPosition, wct); options1 = options1 != null ? options1 : new Bundle(); addActivityOptions(options1, mSideStage); @@ -706,10 +708,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void startWithTask(WindowContainerTransaction wct, int mainTaskId, @Nullable Bundle mainOptions, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { - if (mMainStage.isActive()) { - mMainStage.evictAllChildren(wct); - mSideStage.evictAllChildren(wct); - } else { + if (!mMainStage.isActive()) { // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(wct, false /* reparent */); @@ -882,7 +881,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Set false to avoid record new bounds with old task still on top; mShouldUpdateRecents = false; - mIsSplitEntering = true; + mIsDividerRemoteAnimating = true; if (mSplitRequest == null) { mSplitRequest = new SplitRequest(mainTaskId, mainPendingIntent != null ? mainPendingIntent.getIntent() : null, @@ -975,7 +974,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) { - mIsSplitEntering = false; + mIsDividerRemoteAnimating = false; mShouldUpdateRecents = true; mSplitRequest = null; // If any stage has no child after animation finished, it means that split will display @@ -1020,6 +1019,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideStage.evictInvisibleChildren(wct); } + void prepareEvictChildTasksIfSplitActive(WindowContainerTransaction wct) { + if (mMainStage.isActive()) { + mMainStage.evictAllChildren(wct); + mSideStage.evictAllChildren(wct); + } + } + Bundle resolveStartStage(@StageType int stage, @SplitPosition int position, @Nullable Bundle options, @Nullable WindowContainerTransaction wct) { switch (stage) { @@ -1241,7 +1247,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } }); mShouldUpdateRecents = false; - mIsSplitEntering = false; + mIsDividerRemoteAnimating = false; mSplitLayout.getInvisibleBounds(mTempRect1); if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) { @@ -1584,7 +1590,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, && !ENABLE_SHELL_TRANSITIONS) { // Clear the divider remote animating flag as the divider will be re-rendered to apply // the new rotation config. - mIsSplitEntering = false; + mIsDividerRemoteAnimating = false; mSplitLayout.update(null /* t */); onLayoutSizeChanged(mSplitLayout); } @@ -1634,9 +1640,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) { + // Handle entering split screen while there is a split pair running in the background. if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive() - && !mIsSplitEntering) { - // Handle entring split case here if split already running background. + && mSplitRequest == null) { if (mIsDropEntering) { mSplitLayout.resetDividerPosition(); } else { @@ -1728,7 +1734,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDividerVisible = visible; sendSplitVisibilityChanged(); - if (mIsSplitEntering) { + if (mIsDividerRemoteAnimating) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, " Skip animating divider bar due to it's remote animating."); return; @@ -1748,7 +1754,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, " Skip animating divider bar due to divider leash not ready."); return; } - if (mIsSplitEntering) { + if (mIsDividerRemoteAnimating) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, " Skip animating divider bar due to it's remote animating."); return; @@ -1816,7 +1822,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.flingDividerToDismiss( mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT, EXIT_REASON_APP_FINISHED); - } else if (!isSplitScreenVisible() && !mIsSplitEntering) { + } else if (!isSplitScreenVisible() && mSplitRequest == null) { + // Dismiss split screen in the background once any sides of the split become empty. exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED); } } else if (isSideStage && hasChildren && !mMainStage.isActive()) { @@ -2160,19 +2167,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } else if (isOpening && inFullscreen) { final int activityType = triggerTask.getActivityType(); - if (activityType == ACTIVITY_TYPE_ASSISTANT) { - // We don't want assistant panel to dismiss split screen, so do nothing. - } else if (activityType == ACTIVITY_TYPE_HOME + if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { // Enter overview panel, so start recent transition. mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(), mRecentTransitionFinishedCallback); - } else if (mSplitTransitions.mPendingRecent == null) { - // If split-task is not controlled by recents animation - // and occluded by the other fullscreen task, dismiss both. - prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out); - mSplitTransitions.setDismissTransition( - transition, STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN); } } } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java index ac52235375c4..2e2f569a52b8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java @@ -21,6 +21,7 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT; import android.os.Build; import android.os.SystemClock; import android.util.Pair; +import android.view.SurfaceControl; import androidx.annotation.VisibleForTesting; @@ -75,6 +76,7 @@ public class ShellInit { @VisibleForTesting public void init() { ProtoLog.v(WM_SHELL_INIT, "Initializing Shell Components: %d", mInitCallbacks.size()); + SurfaceControl.setDebugUsageAfterRelease(true); // Init in order of registration for (int i = 0; i < mInitCallbacks.size(); i++) { final Pair<String, Runnable> info = mInitCallbacks.get(i); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index ef405c858e3d..75112b62c1c6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -78,7 +78,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { int mAnimType = 0; final IBinder mTransition; - Transitions.TransitionFinishCallback mFinishCallback = null; Transitions.TransitionHandler mLeftoversHandler = null; WindowContainerTransaction mFinishWCT = null; @@ -241,20 +240,25 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { } if (pipChange == null) { if (mixed.mLeftoversHandler != null) { - return mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info, - startTransaction, finishTransaction, finishCallback); + if (mixed.mLeftoversHandler.startAnimation(mixed.mTransition, + info, startTransaction, finishTransaction, (wct, wctCB) -> { + mActiveTransitions.remove(mixed); + finishCallback.onTransitionFinished(wct, wctCB); + })) { + return true; + } } + mActiveTransitions.remove(mixed); return false; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Splitting PIP into a separate" + " animation because remote-animation likely doesn't support it"); - mixed.mFinishCallback = finishCallback; Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> { --mixed.mInFlightSubAnimations; mixed.joinFinishArgs(wct, wctCB); if (mixed.mInFlightSubAnimations > 0) return; mActiveTransitions.remove(mixed); - mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB); + finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB); }; // Split the transition into 2 parts: the pip part and the rest. mixed.mInFlightSubAnimations = 2; @@ -304,10 +308,10 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { } if (pipChange == null) { // um, something probably went wrong. + mActiveTransitions.remove(mixed); return false; } final boolean isGoingHome = homeIsOpening; - mixed.mFinishCallback = finishCallback; Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> { --mixed.mInFlightSubAnimations; mixed.joinFinishArgs(wct, wctCB); @@ -316,7 +320,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { if (isGoingHome) { mSplitHandler.onTransitionAnimationComplete(); } - mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB); + finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB); }; if (isGoingHome) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed " @@ -408,7 +412,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { unlinkMissingParents(everythingElse); final MixedTransition mixed = new MixedTransition( MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE, transition); - mixed.mFinishCallback = finishCallback; mActiveTransitions.add(mixed); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is a mix of display change " + "and split change."); @@ -420,7 +423,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { mixed.joinFinishArgs(wct, wctCB); if (mixed.mInFlightSubAnimations > 0) return; mActiveTransitions.remove(mixed); - mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */); + finishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */); }; // Dispatch the display change. This will most-likely be taken by the default handler. @@ -447,7 +450,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { // Already done, so no need to end it. return; } - if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { + if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) { + // queue since no actual animation. + } else if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { if (mixed.mAnimType == MixedTransition.ANIM_TYPE_GOING_HOME) { boolean ended = mSplitHandler.end(); // If split couldn't end (because it is remote), then don't end everything else @@ -461,8 +466,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { } else { mPipHandler.end(); } - } else if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) { - // queue + } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) { + mPipHandler.end(); + if (mixed.mLeftoversHandler != null) { + mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, + finishCallback); + } } else { throw new IllegalStateException("Playing a mixed transition with unknown type? " + mixed.mType); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java new file mode 100644 index 000000000000..0386ec38a3ff --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java @@ -0,0 +1,65 @@ +/* + * 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.transition; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.IBinder; +import android.util.Log; +import android.view.SurfaceControl; +import android.window.TransitionInfo; +import android.window.TransitionRequestInfo; +import android.window.WindowContainerTransaction; + +import java.util.ArrayList; + +/** + * A Simple handler that tracks SLEEP transitions. We track them specially since we (ab)use these + * as sentinels for fast-forwarding through animations when the screen is off. + * + * There should only be one SleepHandler and it is used explicitly by {@link Transitions} so we + * don't register it like a normal handler. + */ +class SleepHandler implements Transitions.TransitionHandler { + final ArrayList<IBinder> mSleepTransitions = new ArrayList<>(); + + @Override + public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + startTransaction.apply(); + finishCallback.onTransitionFinished(null, null); + mSleepTransitions.remove(transition); + return true; + } + + @Override + @Nullable + public WindowContainerTransaction handleRequest(@NonNull IBinder transition, + @NonNull TransitionRequestInfo request) { + mSleepTransitions.add(transition); + return new WindowContainerTransaction(); + } + + @Override + public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted, + @Nullable SurfaceControl.Transaction finishTransaction) { + Log.e(Transitions.TAG, "Sleep transition was consumed. This doesn't make sense"); + mSleepTransitions.remove(transition); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java index 8d29901c3a07..bcc37baa5b00 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java @@ -143,8 +143,12 @@ public class TransitionAnimationHelper { Animation a = null; if (animAttr != 0) { if (overrideType == ANIM_FROM_STYLE && !isTask) { - a = loadCustomActivityTransition(animAttr, options, enter, transitionAnimation); - if (a == null) { + final TransitionInfo.AnimationOptions.CustomActivityTransition customTransition = + getCustomActivityTransition(animAttr, options); + if (customTransition != null) { + a = loadCustomActivityTransition( + customTransition, options, enter, transitionAnimation); + } else { a = transitionAnimation .loadAnimationAttr(options.getPackageName(), options.getAnimations(), animAttr, translucent); @@ -161,10 +165,8 @@ public class TransitionAnimationHelper { return a; } - static Animation loadCustomActivityTransition(int animAttr, - TransitionInfo.AnimationOptions options, boolean enter, - TransitionAnimation transitionAnimation) { - Animation a = null; + static TransitionInfo.AnimationOptions.CustomActivityTransition getCustomActivityTransition( + int animAttr, TransitionInfo.AnimationOptions options) { boolean isOpen = false; switch (animAttr) { case R.styleable.WindowAnimation_activityOpenEnterAnimation: @@ -178,17 +180,19 @@ public class TransitionAnimationHelper { return null; } - final TransitionInfo.AnimationOptions.CustomActivityTransition transitionAnim = - options.getCustomActivityTransition(isOpen); - if (transitionAnim != null) { - a = transitionAnimation.loadAppTransitionAnimation(options.getPackageName(), - enter ? transitionAnim.getCustomEnterResId() - : transitionAnim.getCustomExitResId()); - if (a != null && transitionAnim.getCustomBackgroundColor() != 0) { - a.setBackdropColor(transitionAnim.getCustomBackgroundColor()); - } - } + return options.getCustomActivityTransition(isOpen); + } + static Animation loadCustomActivityTransition( + @NonNull TransitionInfo.AnimationOptions.CustomActivityTransition transitionAnim, + TransitionInfo.AnimationOptions options, boolean enter, + TransitionAnimation transitionAnimation) { + final Animation a = transitionAnimation.loadAppTransitionAnimation(options.getPackageName(), + enter ? transitionAnim.getCustomEnterResId() + : transitionAnim.getCustomExitResId()); + if (a != null && transitionAnim.getCustomBackgroundColor() != 0) { + a.setBackdropColor(transitionAnim.getCustomBackgroundColor()); + } return a; } 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 3b154d1cda83..155990a40836 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 @@ -21,6 +21,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.fixScale; @@ -124,6 +125,7 @@ public class Transitions implements RemoteCallable<Transitions> { private final DisplayController mDisplayController; private final ShellController mShellController; private final ShellTransitionImpl mImpl = new ShellTransitionImpl(); + private final SleepHandler mSleepHandler = new SleepHandler(); private boolean mIsRegistered = false; @@ -137,6 +139,14 @@ public class Transitions implements RemoteCallable<Transitions> { private float mTransitionAnimationScaleSetting = 1.0f; + /** + * How much time we allow for an animation to finish itself on sleep. If it takes longer, we + * will force-finish it (on this end) which may leave it in a bad state but won't hang the + * device. This needs to be pretty small because it is an allowance for each queued animation, + * however it can't be too small since there is some potential IPC involved. + */ + private static final int SLEEP_ALLOWANCE_MS = 120; + private static final class ActiveTransition { IBinder mToken; TransitionHandler mHandler; @@ -478,11 +488,29 @@ public class Transitions implements RemoteCallable<Transitions> { + Arrays.toString(mActiveTransitions.stream().map( activeTransition -> activeTransition.mToken).toArray())); } + final ActiveTransition active = mActiveTransitions.get(activeIdx); for (int i = 0; i < mObservers.size(); ++i) { mObservers.get(i).onTransitionReady(transitionToken, info, t, finishT); } + if (info.getType() == TRANSIT_SLEEP) { + if (activeIdx > 0) { + active.mInfo = info; + active.mStartT = t; + active.mFinishT = finishT; + if (!info.getRootLeash().isValid()) { + // Shell has some debug settings which makes calling binders with invalid + // surfaces crash, so replace it with a "real" one. + info.setRootLeash(new SurfaceControl.Builder().setName("Invalid") + .setContainerLayer().build(), 0, 0); + } + // Sleep starts a process of forcing all prior transitions to finish immediately + finishForSleep(null /* forceFinish */); + return; + } + } + // Allow to notify keyguard un-occluding state to KeyguardService, which can happen while // screen-off, so there might no visibility change involved. if (!info.getRootLeash().isValid() && info.getType() != TRANSIT_KEYGUARD_UNOCCLUDE) { @@ -527,7 +555,6 @@ public class Transitions implements RemoteCallable<Transitions> { return; } - final ActiveTransition active = mActiveTransitions.get(activeIdx); active.mInfo = info; active.mStartT = t; active.mFinishT = finishT; @@ -772,6 +799,12 @@ public class Transitions implements RemoteCallable<Transitions> { ++mergeIdx; continue; } + if (mergeCandidate.mInfo == null) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition merge candidate" + + " %s is not ready yet", mergeCandidate.mToken); + // The later transition should not be merged if the prior one is not ready. + return; + } if (mergeCandidate.mMerged) { throw new IllegalStateException("Can't merge a transition after not-merging" + " a preceding one."); @@ -797,23 +830,30 @@ public class Transitions implements RemoteCallable<Transitions> { } final ActiveTransition active = new ActiveTransition(); WindowContainerTransaction wct = null; - for (int i = mHandlers.size() - 1; i >= 0; --i) { - wct = mHandlers.get(i).handleRequest(transitionToken, request); - if (wct != null) { - active.mHandler = mHandlers.get(i); - break; + + // If we have sleep, we use a special handler and we try to finish everything ASAP. + if (request.getType() == TRANSIT_SLEEP) { + mSleepHandler.handleRequest(transitionToken, request); + active.mHandler = mSleepHandler; + } else { + for (int i = mHandlers.size() - 1; i >= 0; --i) { + wct = mHandlers.get(i).handleRequest(transitionToken, request); + if (wct != null) { + active.mHandler = mHandlers.get(i); + break; + } } - } - if (request.getDisplayChange() != null) { - TransitionRequestInfo.DisplayChange change = request.getDisplayChange(); - if (change.getEndRotation() != change.getStartRotation()) { - // Is a rotation, so dispatch to all displayChange listeners - if (wct == null) { - wct = new WindowContainerTransaction(); + if (request.getDisplayChange() != null) { + TransitionRequestInfo.DisplayChange change = request.getDisplayChange(); + if (change.getEndRotation() != change.getStartRotation()) { + // Is a rotation, so dispatch to all displayChange listeners + if (wct == null) { + wct = new WindowContainerTransaction(); + } + mDisplayController.getChangeController().dispatchOnDisplayChange(wct, + change.getDisplayId(), change.getStartRotation(), + change.getEndRotation(), null /* newDisplayAreaInfo */); } - mDisplayController.getChangeController().dispatchOnDisplayChange(wct, - change.getDisplayId(), change.getStartRotation(), change.getEndRotation(), - null /* newDisplayAreaInfo */); } } mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct); @@ -840,6 +880,56 @@ public class Transitions implements RemoteCallable<Transitions> { } /** + * Finish running animations (almost) immediately when a SLEEP transition comes in. We use this + * as both a way to reduce unnecessary work (animations not visible while screen off) and as a + * failsafe to unblock "stuck" animations (in particular remote animations). + * + * This works by "merging" the sleep transition into the currently-playing transition (even if + * its out-of-order) -- turning SLEEP into a signal. If the playing transition doesn't finish + * within `SLEEP_ALLOWANCE_MS` from this merge attempt, this will then finish it directly (and + * send an abort/consumed message). + * + * This is then repeated until there are no more pending sleep transitions. + * + * @param forceFinish When non-null, this is the transition that we last sent the SLEEP merge + * signal to -- so it will be force-finished if it's still running. + */ + private void finishForSleep(@Nullable IBinder forceFinish) { + if (mActiveTransitions.isEmpty() || mSleepHandler.mSleepTransitions.isEmpty()) { + return; + } + if (forceFinish != null && mActiveTransitions.get(0).mToken == forceFinish) { + Log.e(TAG, "Forcing transition to finish due to sleep timeout: " + + mActiveTransitions.get(0).mToken); + onFinish(mActiveTransitions.get(0).mToken, null, null, true); + } + final SurfaceControl.Transaction dummyT = new SurfaceControl.Transaction(); + while (!mActiveTransitions.isEmpty() && !mSleepHandler.mSleepTransitions.isEmpty()) { + final ActiveTransition playing = mActiveTransitions.get(0); + int sleepIdx = findActiveTransition(mSleepHandler.mSleepTransitions.get(0)); + if (sleepIdx >= 0) { + // Try to signal that we are sleeping by attempting to merge the sleep transition + // into the playing one. + final ActiveTransition nextSleep = mActiveTransitions.get(sleepIdx); + playing.mHandler.mergeAnimation(nextSleep.mToken, nextSleep.mInfo, dummyT, + playing.mToken, (wct, cb) -> {}); + } else { + Log.e(TAG, "Couldn't find sleep transition in active list: " + + mSleepHandler.mSleepTransitions.get(0)); + } + // it's possible to complete immediately. If that happens, just repeat the signal + // loop until we either finish everything or start playing an animation that isn't + // finishing immediately. + if (!mActiveTransitions.isEmpty() && mActiveTransitions.get(0) == playing) { + // Give it a (very) short amount of time to process it before forcing. + mMainExecutor.executeDelayed( + () -> finishForSleep(playing.mToken), SLEEP_ALLOWANCE_MS); + break; + } + } + } + + /** * Interface for a callback that must be called after a TransitionHandler finishes playing an * animation. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java index 145f759d4de2..8c6e1e7f5f1b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java @@ -16,18 +16,40 @@ package com.android.wm.shell.util; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.view.RemoteAnimationTarget.MODE_CHANGING; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; +import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; +import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; + +import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.WindowConfiguration; +import android.graphics.Rect; +import android.util.ArrayMap; +import android.util.SparseBooleanArray; +import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; +import java.util.function.Predicate; + /** Various utility functions for transitions. */ public class TransitionUtil { @@ -54,4 +76,189 @@ public class TransitionUtil { return false; } + /** Returns `true` if `change` is a wallpaper. */ + public static boolean isWallpaper(TransitionInfo.Change change) { + return (change.getTaskInfo() == null) + && change.hasFlags(FLAG_IS_WALLPAPER) + && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY); + } + + /** Returns `true` if `change` is not an app window or wallpaper. */ + public static boolean isNonApp(TransitionInfo.Change change) { + return (change.getTaskInfo() == null) + && !change.hasFlags(FLAG_IS_WALLPAPER) + && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY); + } + + /** + * Filter that selects leaf-tasks only. THIS IS ORDER-DEPENDENT! For it to work properly, you + * MUST call `test` in the same order that the changes appear in the TransitionInfo. + */ + public static class LeafTaskFilter implements Predicate<TransitionInfo.Change> { + private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray(); + + @Override + public boolean test(TransitionInfo.Change change) { + final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + // Children always come before parent since changes are in top-to-bottom z-order. + if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) { + // has children, so not a leaf. Skip. + return false; + } + if (taskInfo.hasParentTask()) { + mChildTaskTargets.put(taskInfo.parentTaskId, true); + } + return true; + } + } + + + private static int newModeToLegacyMode(int newMode) { + switch (newMode) { + case WindowManager.TRANSIT_OPEN: + case WindowManager.TRANSIT_TO_FRONT: + return MODE_OPENING; + case WindowManager.TRANSIT_CLOSE: + case WindowManager.TRANSIT_TO_BACK: + return MODE_CLOSING; + default: + return MODE_CHANGING; + } + } + + /** + * Very similar to Transitions#setupAnimHierarchy but specialized for leashes. + */ + @SuppressLint("NewApi") + private static void setupLeash(@NonNull SurfaceControl leash, + @NonNull TransitionInfo.Change change, int layer, + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { + final boolean isOpening = TransitionUtil.isOpeningType(info.getType()); + // Put animating stuff above this line and put static stuff below it. + int zSplitLine = info.getChanges().size(); + // changes should be ordered top-to-bottom in z + final int mode = change.getMode(); + + t.reparent(leash, info.getRootLeash()); + final Rect absBounds = + (mode == TRANSIT_OPEN) ? change.getEndAbsBounds() : change.getStartAbsBounds(); + t.setPosition(leash, absBounds.left - info.getRootOffset().x, + absBounds.top - info.getRootOffset().y); + + // Put all the OPEN/SHOW on top + if (TransitionUtil.isOpeningType(mode)) { + if (isOpening) { + t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); + if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) { + // if transferred, it should be left visible. + t.setAlpha(leash, 0.f); + } + } else { + // put on bottom and leave it visible + t.setLayer(leash, zSplitLine - layer); + } + } else if (TransitionUtil.isClosingType(mode)) { + if (isOpening) { + // put on bottom and leave visible + t.setLayer(leash, zSplitLine - layer); + } else { + // put on top + t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); + } + } else { // CHANGE + t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); + } + } + + @SuppressLint("NewApi") + private static SurfaceControl createLeash(TransitionInfo info, TransitionInfo.Change change, + int order, SurfaceControl.Transaction t) { + // TODO: once we can properly sync transactions across process, then get rid of this leash. + if (change.getParent() != null && (change.getFlags() & FLAG_IS_WALLPAPER) != 0) { + // Special case for wallpaper atm. Normally these are left alone; but, a quirk of + // making leashes means we have to handle them specially. + return change.getLeash(); + } + SurfaceControl leashSurface = new SurfaceControl.Builder() + .setName(change.getLeash().toString() + "_transition-leash") + .setContainerLayer() + // Initial the surface visible to respect the visibility of the original surface. + .setHidden(false) + .setParent(info.getRootLeash()) + .build(); + // Copied Transitions setup code (which expects bottom-to-top order, so we swap here) + setupLeash(leashSurface, change, info.getChanges().size() - order, info, t); + t.reparent(change.getLeash(), leashSurface); + t.setAlpha(change.getLeash(), 1.0f); + t.show(change.getLeash()); + t.setPosition(change.getLeash(), 0, 0); + t.setLayer(change.getLeash(), 0); + return leashSurface; + } + + /** + * Creates a new RemoteAnimationTarget from the provided change info + */ + public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order, + TransitionInfo info, SurfaceControl.Transaction t, + @Nullable ArrayMap<SurfaceControl, SurfaceControl> leashMap) { + final SurfaceControl leash = createLeash(info, change, order, t); + if (leashMap != null) { + leashMap.put(change.getLeash(), leash); + } + return newTarget(change, order, leash); + } + + /** + * Creates a new RemoteAnimationTarget from the provided change and leash + */ + public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order, + SurfaceControl leash) { + int taskId; + boolean isNotInRecents; + ActivityManager.RunningTaskInfo taskInfo; + WindowConfiguration windowConfiguration; + + taskInfo = change.getTaskInfo(); + if (taskInfo != null) { + taskId = taskInfo.taskId; + isNotInRecents = !taskInfo.isRunning; + windowConfiguration = taskInfo.configuration.windowConfiguration; + } else { + taskId = INVALID_TASK_ID; + isNotInRecents = true; + windowConfiguration = new WindowConfiguration(); + } + + Rect localBounds = new Rect(change.getEndAbsBounds()); + localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y); + + RemoteAnimationTarget target = new RemoteAnimationTarget( + taskId, + newModeToLegacyMode(change.getMode()), + // TODO: once we can properly sync transactions across process, + // then get rid of this leash. + leash, + (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0, + null, + // TODO(shell-transitions): we need to send content insets? evaluate how its used. + new Rect(0, 0, 0, 0), + order, + null, + localBounds, + new Rect(change.getEndAbsBounds()), + windowConfiguration, + isNotInRecents, + null, + new Rect(change.getStartAbsBounds()), + taskInfo, + change.getAllowEnterPip(), + (change.getFlags() & FLAG_IS_DIVIDER_BAR) != 0 + ? TYPE_DOCK_DIVIDER : INVALID_WINDOW_TYPE + ); + target.setWillShowImeOnTarget( + (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0); + target.setRotationChange(change.getEndRotation() - change.getStartRotation()); + return target; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 0779f1d72551..72da1089c91c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -74,6 +74,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private boolean mDesktopActive; private AdditionalWindow mHandleMenu; private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width; + private final int mHandleMenuShadowRadiusId = R.dimen.caption_menu_shadow_radius; + private final int mHandleMenuCornerRadiusId = R.dimen.caption_menu_corner_radius; private PointF mHandleMenuPosition = new PointF(); DesktopModeWindowDecoration( @@ -353,19 +355,16 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .windowConfiguration.getBounds().width(); final int menuWidth = loadDimensionPixelSize(resources, mHandleMenuWidthId); final int menuHeight = loadDimensionPixelSize(resources, mCaptionMenuHeightId); - - // Elevation gives the appearance of a changed x/y coordinate; this is to fix that - int elevationOffset = 2 * loadDimensionPixelSize(resources, - R.dimen.caption_menu_elevation); + final int shadowRadius = loadDimensionPixelSize(resources, mHandleMenuShadowRadiusId); + final int cornerRadius = loadDimensionPixelSize(resources, mHandleMenuCornerRadiusId); final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) - - mResult.mDecorContainerOffsetX - elevationOffset; - final int y = - mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY - elevationOffset; + - mResult.mDecorContainerOffsetX; + final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; mHandleMenuPosition.set(x, y); String namePrefix = "Caption Menu"; mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y, - menuWidth, menuHeight, 2 * elevationOffset); + menuWidth, menuHeight, shadowRadius, cornerRadius); mSyncQueue.runInSync(transaction -> { transaction.merge(t); t.close(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 91b0aa193aad..7a7ac476879e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -391,11 +391,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param yPos y position of new window * @param width width of new window * @param height height of new window - * @param cropPadding padding to add to window crop to ensure shadows display properly - * @return + * @param shadowRadius radius of the shadow of the new window + * @param cornerRadius radius of the corners of the new window + * @return the {@link AdditionalWindow} that was added. */ AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, - int xPos, int yPos, int width, int height, int cropPadding) { + int xPos, int yPos, int width, int height, int shadowRadius, int cornerRadius) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) @@ -404,9 +405,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); - t.setPosition( - windowSurfaceControl, xPos, yPos) - .setWindowCrop(windowSurfaceControl, width + cropPadding, height + cropPadding) + t.setPosition(windowSurfaceControl, xPos, yPos) + .setWindowCrop(windowSurfaceControl, width, height) + .setShadowRadius(windowSurfaceControl, shadowRadius) + .setCornerRadius(windowSurfaceControl, cornerRadius) .show(windowSurfaceControl); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt index da80c6f46976..5c9920970761 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt @@ -80,7 +80,8 @@ class EnterSplitScreenByDragFromTaskbar(flicker: FlickerTest) : SplitScreenBase( @IwTest(focusArea = "sysui") @Presubmit @Test - fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false) + fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false, + appExistAtStart = false) @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml index fac04614d945..47a116be1b66 100644 --- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml @@ -20,6 +20,7 @@ package="com.android.wm.shell.tests"> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.VIBRATE"/> <application android:debuggable="true" android:largeHeap="true"> <uses-library android:name="android.test.mock" /> diff --git a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml index 27d40b2b25b2..aa1b24189274 100644 --- a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml +++ b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml @@ -24,4 +24,6 @@ <dimen name="test_window_decor_bottom_outset">40dp</dimen> <dimen name="test_window_decor_shadow_radius">5dp</dimen> <dimen name="test_window_decor_resize_handle">10dp</dimen> + <dimen name="test_caption_menu_shadow_radius">4dp</dimen> + <dimen name="test_caption_menu_corner_radius">20dp</dimen> </resources>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index ed0ac5f1cdca..3901dabcaec8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -284,41 +284,6 @@ public class SplitTransitionTests extends ShellTestCase { @Test @UiThreadTest - public void testDismissFromBeingOccluded() { - enterSplit(); - - ActivityManager.RunningTaskInfo normalTask = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FULLSCREEN) - .build(); - - // Create a request to bring a normal task forward - TransitionRequestInfo request = - new TransitionRequestInfo(TRANSIT_TO_FRONT, normalTask, null); - IBinder transition = mock(IBinder.class); - WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request); - - assertTrue(containsSplitExit(result)); - - // make sure we haven't made any local changes yet (need to wait until transition is ready) - assertTrue(mStageCoordinator.isSplitScreenVisible()); - - // simulate the transition - TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, 0) - .addChange(TRANSIT_TO_FRONT, normalTask) - .addChange(TRANSIT_TO_BACK, mMainChild) - .addChange(TRANSIT_TO_BACK, mSideChild) - .build(); - mMainStage.onTaskVanished(mMainChild); - mSideStage.onTaskVanished(mSideChild); - mStageCoordinator.startAnimation(transition, info, - mock(SurfaceControl.Transaction.class), - mock(SurfaceControl.Transaction.class), - mock(Transitions.TransitionFinishCallback.class)); - assertFalse(mStageCoordinator.isSplitScreenVisible()); - } - - @Test - @UiThreadTest public void testDismissFromMultiWindowSupport() { enterSplit(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index 6c9b186b7ede..e63bbeb05575 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -563,6 +563,33 @@ public class ShellTransitionTests extends ShellTestCase { assertEquals(0, mDefaultHandler.activeCount()); } + + @Test + public void testTransitionMergingOnFinish() { + final Transitions transitions = createTestTransitions(); + transitions.replaceDefaultHandlerForTest(mDefaultHandler); + + // The current transition. + final IBinder transitToken1 = new Binder(); + requestStartTransition(transitions, transitToken1); + onTransitionReady(transitions, transitToken1); + + // The next ready transition. + final IBinder transitToken2 = new Binder(); + requestStartTransition(transitions, transitToken2); + onTransitionReady(transitions, transitToken2); + + // The non-ready merge candidate. + final IBinder transitTokenNotReady = new Binder(); + requestStartTransition(transitions, transitTokenNotReady); + + mDefaultHandler.setSimulateMerge(true); + mDefaultHandler.mFinishes.get(0).onTransitionFinished(null /* wct */, null /* wctCB */); + + // Make sure that the non-ready transition is not merged. + assertEquals(0, mDefaultHandler.mergeCount()); + } + @Test public void testTransitionOrderMatchesCore() { Transitions transitions = createTestTransitions(); @@ -1036,6 +1063,21 @@ public class ShellTransitionTests extends ShellTestCase { } } + private static void requestStartTransition(Transitions transitions, IBinder token) { + transitions.requestStartTransition(token, + new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */)); + } + + private static void onTransitionReady(Transitions transitions, IBinder token) { + transitions.onTransitionReady(token, createTransitionInfo(), + mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class)); + } + + private static TransitionInfo createTransitionInfo() { + return new TransitionInfoBuilder(TRANSIT_OPEN) + .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build(); + } + private static SurfaceControl createMockSurface(boolean valid) { SurfaceControl sc = mock(SurfaceControl.class); doReturn(valid).when(sc).isValid(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index b80edcece512..7e39b5b8f2ce 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -108,6 +108,8 @@ public class WindowDecorationTests extends ShellTestCase { private SurfaceControl.Transaction mMockSurfaceControlAddWindowT; private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams(); private int mCaptionMenuWidthId; + private int mCaptionMenuShadowRadiusId; + private int mCaptionMenuCornerRadiusId; @Before public void setUp() { @@ -118,6 +120,8 @@ public class WindowDecorationTests extends ShellTestCase { mRelayoutParams.mLayoutResId = 0; mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height; mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width; + mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius; + mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius; mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius; doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory) @@ -431,7 +435,19 @@ public class WindowDecorationTests extends ShellTestCase { verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface); verify(additionalWindowSurfaceBuilder).build(); verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40); - verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 442, 74); + final int width = WindowDecoration.loadDimensionPixelSize( + mContext.getResources(), mCaptionMenuWidthId); + final int height = WindowDecoration.loadDimensionPixelSize( + mContext.getResources(), mRelayoutParams.mCaptionHeightId); + verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height); + final int shadowRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(), + mCaptionMenuShadowRadiusId); + verify(mMockSurfaceControlAddWindowT) + .setShadowRadius(additionalWindowSurface, shadowRadius); + final int cornerRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(), + mCaptionMenuCornerRadiusId); + verify(mMockSurfaceControlAddWindowT) + .setCornerRadius(additionalWindowSurface, cornerRadius); verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface); verify(mMockSurfaceControlViewHostFactory, Mockito.times(2)) .create(any(), eq(defaultDisplay), any()); @@ -559,13 +575,15 @@ public class WindowDecorationTests extends ShellTestCase { int y = mRelayoutParams.mCaptionY; int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId); + int shadowRadius = loadDimensionPixelSize(resources, mCaptionMenuShadowRadiusId); + int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId); String name = "Test Window"; WindowDecoration.AdditionalWindow additionalWindow = addWindow(R.layout.desktop_mode_decor_handle_menu, name, mMockSurfaceControlAddWindowT, x - mRelayoutResult.mDecorContainerOffsetX, y - mRelayoutResult.mDecorContainerOffsetY, - width, height, 10); + width, height, shadowRadius, cornerRadius); return additionalWindow; } } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 536bb49675f1..7228b895ebc4 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -338,6 +338,7 @@ cc_defaults { "jni/android_util_PathParser.cpp", "jni/Bitmap.cpp", + "jni/BufferUtils.cpp", "jni/HardwareBufferHelpers.cpp", "jni/BitmapFactory.cpp", "jni/ByteBufferStreamAdaptor.cpp", @@ -374,6 +375,7 @@ cc_defaults { "jni/text/LineBreaker.cpp", "jni/text/MeasuredText.cpp", "jni/text/TextShaper.cpp", + "jni/text/GraphemeBreak.cpp", ], header_libs: [ diff --git a/libs/hwui/Mesh.h b/libs/hwui/Mesh.h index 983681707415..13e3c8e7bf77 100644 --- a/libs/hwui/Mesh.h +++ b/libs/hwui/Mesh.h @@ -104,33 +104,31 @@ private: class Mesh { public: - Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode, const void* vertexBuffer, - size_t vertexBufferSize, jint vertexCount, jint vertexOffset, + Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode, + std::vector<uint8_t>&& vertexBufferData, jint vertexCount, jint vertexOffset, std::unique_ptr<MeshUniformBuilder> builder, const SkRect& bounds) : mMeshSpec(meshSpec) , mMode(mode) + , mVertexBufferData(std::move(vertexBufferData)) , mVertexCount(vertexCount) , mVertexOffset(vertexOffset) , mBuilder(std::move(builder)) - , mBounds(bounds) { - copyToVector(mVertexBufferData, vertexBuffer, vertexBufferSize); - } + , mBounds(bounds) {} - Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode, const void* vertexBuffer, - size_t vertexBufferSize, jint vertexCount, jint vertexOffset, const void* indexBuffer, - size_t indexBufferSize, jint indexCount, jint indexOffset, + Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode, + std::vector<uint8_t>&& vertexBufferData, jint vertexCount, jint vertexOffset, + std::vector<uint8_t>&& indexBuffer, jint indexCount, jint indexOffset, std::unique_ptr<MeshUniformBuilder> builder, const SkRect& bounds) : mMeshSpec(meshSpec) , mMode(mode) + , mVertexBufferData(std::move(vertexBufferData)) , mVertexCount(vertexCount) , mVertexOffset(vertexOffset) + , mIndexBufferData(std::move(indexBuffer)) , mIndexCount(indexCount) , mIndexOffset(indexOffset) , mBuilder(std::move(builder)) - , mBounds(bounds) { - copyToVector(mVertexBufferData, vertexBuffer, vertexBufferSize); - copyToVector(mIndexBufferData, indexBuffer, indexBufferSize); - } + , mBounds(bounds) {} Mesh(Mesh&&) = default; @@ -180,13 +178,6 @@ public: MeshUniformBuilder* uniformBuilder() { return mBuilder.get(); } private: - void copyToVector(std::vector<uint8_t>& dst, const void* src, size_t srcSize) { - if (src) { - dst.resize(srcSize); - memcpy(dst.data(), src, srcSize); - } - } - sk_sp<SkMeshSpecification> mMeshSpec; int mMode = 0; diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp index b7a15633ff6d..770822a049b7 100644 --- a/libs/hwui/apex/LayoutlibLoader.cpp +++ b/libs/hwui/apex/LayoutlibLoader.cpp @@ -66,6 +66,7 @@ extern int register_android_graphics_fonts_FontFamily(JNIEnv* env); extern int register_android_graphics_text_LineBreaker(JNIEnv* env); extern int register_android_graphics_text_MeasuredText(JNIEnv* env); extern int register_android_graphics_text_TextShaper(JNIEnv* env); +extern int register_android_graphics_text_GraphemeBreak(JNIEnv* env); extern int register_android_util_PathParser(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); @@ -125,6 +126,8 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = { {"android.graphics.text.MeasuredText", REG_JNI(register_android_graphics_text_MeasuredText)}, {"android.graphics.text.TextRunShaper", REG_JNI(register_android_graphics_text_TextShaper)}, + {"android.graphics.text.GraphemeBreak", + REG_JNI(register_android_graphics_text_GraphemeBreak)}, {"android.util.PathParser", REG_JNI(register_android_util_PathParser)}, }; diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp index c509ed4dfd21..09ae7e78fe23 100644 --- a/libs/hwui/apex/jni_runtime.cpp +++ b/libs/hwui/apex/jni_runtime.cpp @@ -77,6 +77,7 @@ extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env); extern int register_android_graphics_text_MeasuredText(JNIEnv* env); extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_graphics_text_TextShaper(JNIEnv *env); +extern int register_android_graphics_text_GraphemeBreak(JNIEnv* env); extern int register_android_graphics_MeshSpecification(JNIEnv* env); extern int register_android_graphics_Mesh(JNIEnv* env); @@ -148,6 +149,7 @@ extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env); REG_JNI(register_android_graphics_text_MeasuredText), REG_JNI(register_android_graphics_text_LineBreaker), REG_JNI(register_android_graphics_text_TextShaper), + REG_JNI(register_android_graphics_text_GraphemeBreak), REG_JNI(register_android_graphics_MeshSpecification), REG_JNI(register_android_graphics_Mesh), diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index ecf6cfc05444..b3eaa0ce5979 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -463,6 +463,13 @@ bool Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* str if (hasGainmap() && format == JavaCompressFormat::Jpeg) { SkBitmap baseBitmap = getSkBitmap(); SkBitmap gainmapBitmap = gainmap()->bitmap->getSkBitmap(); + if (gainmapBitmap.colorType() == SkColorType::kAlpha_8_SkColorType) { + SkBitmap greyGainmap; + auto greyInfo = gainmapBitmap.info().makeColorType(SkColorType::kGray_8_SkColorType); + greyGainmap.setInfo(greyInfo, gainmapBitmap.rowBytes()); + greyGainmap.setPixelRef(sk_ref_sp(gainmapBitmap.pixelRef()), 0, 0); + gainmapBitmap = std::move(greyGainmap); + } SkJpegEncoder::Options options{.fQuality = quality}; return SkJpegGainmapEncoder::EncodeHDRGM(stream, baseBitmap.pixmap(), options, gainmapBitmap.pixmap(), options, gainmap()->info); diff --git a/libs/hwui/jni/BufferUtils.cpp b/libs/hwui/jni/BufferUtils.cpp new file mode 100644 index 000000000000..3eb08d7552da --- /dev/null +++ b/libs/hwui/jni/BufferUtils.cpp @@ -0,0 +1,130 @@ +/* + * 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. + */ +#include "BufferUtils.h" + +#include "graphics_jni_helpers.h" + +static void copyToVector(std::vector<uint8_t>& dst, const void* src, size_t srcSize) { + if (src) { + dst.resize(srcSize); + memcpy(dst.data(), src, srcSize); + } +} + +/** + * This code is taken and modified from com_google_android_gles_jni_GLImpl.cpp to extract data + * from a java.nio.Buffer. + */ +static void* getDirectBufferPointer(JNIEnv* env, jobject buffer) { + if (buffer == nullptr) { + return nullptr; + } + + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "Must use a native order direct Buffer"); + return nullptr; + } + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); +} + +static void releasePointer(JNIEnv* env, jarray array, void* data, jboolean commit) { + env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT); +} + +static void* getPointer(JNIEnv* env, jobject buffer, jarray* array, jint* remaining, jint* offset) { + jint position; + jint limit; + jint elementSizeShift; + + jlong pointer; + pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift); + *remaining = (limit - position) << elementSizeShift; + if (pointer != 0L) { + *array = nullptr; + pointer += position << elementSizeShift; + return reinterpret_cast<void*>(pointer); + } + + *array = jniGetNioBufferBaseArray(env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(env, buffer); + return nullptr; +} + +/** + * This is a copy of + * static void android_glBufferData__IILjava_nio_Buffer_2I + * from com_google_android_gles_jni_GLImpl.cpp + */ +static void setIndirectData(JNIEnv* env, size_t size, jobject data_buf, + std::vector<uint8_t>& result) { + jint exception = 0; + const char* exceptionType = nullptr; + const char* exceptionMessage = nullptr; + jarray array = nullptr; + jint bufferOffset = 0; + jint remaining; + void* data = 0; + char* dataBase = nullptr; + + if (data_buf) { + data = getPointer(env, data_buf, (jarray*)&array, &remaining, &bufferOffset); + if (remaining < size) { + exception = 1; + exceptionType = "java/lang/IllegalArgumentException"; + exceptionMessage = "remaining() < size < needed"; + goto exit; + } + } + if (data_buf && data == nullptr) { + dataBase = (char*)env->GetPrimitiveArrayCritical(array, (jboolean*)0); + data = (void*)(dataBase + bufferOffset); + } + + copyToVector(result, data, size); + +exit: + if (array) { + releasePointer(env, array, (void*)dataBase, JNI_FALSE); + } + if (exception) { + jniThrowException(env, exceptionType, exceptionMessage); + } +} + +std::vector<uint8_t> copyJavaNioBufferToVector(JNIEnv* env, jobject buffer, size_t size, + jboolean isDirect) { + std::vector<uint8_t> data; + if (buffer == nullptr) { + jniThrowNullPointerException(env); + } else { + if (isDirect) { + void* directBufferPtr = getDirectBufferPointer(env, buffer); + if (directBufferPtr) { + copyToVector(data, directBufferPtr, size); + } + } else { + setIndirectData(env, size, buffer, data); + } + } + return data; +} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ColorScheme.kt b/libs/hwui/jni/BufferUtils.h index b2489fd57b5d..b43c320b7771 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ColorScheme.kt +++ b/libs/hwui/jni/BufferUtils.h @@ -13,18 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#ifndef BUFFERUTILS_H_ +#define BUFFERUTILS_H_ -package com.android.credentialmanager.common.ui +#include <jni.h> -import androidx.compose.material3.ColorScheme -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import kotlin.math.ln +#include <vector> -fun ColorScheme.surfaceColorAtElevation(elevation: Dp): Color { - if (elevation == 0.dp) return surface - val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f - return surfaceTint.copy(alpha = alpha).compositeOver(surface) -}
\ No newline at end of file +/** + * Helper method to load a java.nio.Buffer instance into a vector. This handles + * both direct and indirect buffers and promptly releases any critical arrays that + * have been retrieved in order to avoid potential jni exceptions due to interleaved + * jni calls between get/release primitive method invocations. + */ +std::vector<uint8_t> copyJavaNioBufferToVector(JNIEnv* env, jobject buffer, size_t size, + jboolean isDirect); + +#endif // BUFFERUTILS_H_ diff --git a/libs/hwui/jni/android_graphics_Mesh.cpp b/libs/hwui/jni/android_graphics_Mesh.cpp index 04339dc8b9a5..5cb43e54e499 100644 --- a/libs/hwui/jni/android_graphics_Mesh.cpp +++ b/libs/hwui/jni/android_graphics_Mesh.cpp @@ -14,172 +14,18 @@ * limitations under the License. */ -#include <GrDirectContext.h> #include <Mesh.h> #include <SkMesh.h> #include <jni.h> -#include <log/log.h> #include <utility> +#include "BufferUtils.h" #include "GraphicsJNI.h" #include "graphics_jni_helpers.h" #define gIndexByteSize 2 -// A smart pointer that provides read only access to Java.nio.Buffer. This handles both -// direct and indrect buffers, allowing access to the underlying data in both -// situations. If passed a null buffer, we will throw NullPointerException, -// and c_data will return nullptr. -// -// This class draws from com_google_android_gles_jni_GLImpl.cpp for Buffer to void * -// conversion. -class ScopedJavaNioBuffer { -public: - ScopedJavaNioBuffer(JNIEnv* env, jobject buffer, size_t size, jboolean isDirect) - : mEnv(env), mBuffer(buffer) { - if (buffer == nullptr) { - mDataBase = nullptr; - mData = nullptr; - jniThrowNullPointerException(env); - } else { - mArray = (jarray) nullptr; - if (isDirect) { - mData = getDirectBufferPointer(mEnv, mBuffer); - } else { - mData = setIndirectData(size); - } - } - } - - ScopedJavaNioBuffer(ScopedJavaNioBuffer&& rhs) noexcept { *this = std::move(rhs); } - - ~ScopedJavaNioBuffer() { reset(); } - - void reset() { - if (mDataBase) { - releasePointer(mEnv, mArray, mDataBase, JNI_FALSE); - mDataBase = nullptr; - } - } - - ScopedJavaNioBuffer& operator=(ScopedJavaNioBuffer&& rhs) noexcept { - if (this != &rhs) { - reset(); - - mEnv = rhs.mEnv; - mBuffer = rhs.mBuffer; - mDataBase = rhs.mDataBase; - mData = rhs.mData; - mArray = rhs.mArray; - rhs.mEnv = nullptr; - rhs.mData = nullptr; - rhs.mBuffer = nullptr; - rhs.mArray = nullptr; - rhs.mDataBase = nullptr; - } - return *this; - } - - const void* data() const { return mData; } - -private: - /** - * This code is taken and modified from com_google_android_gles_jni_GLImpl.cpp to extract data - * from a java.nio.Buffer. - */ - void* getDirectBufferPointer(JNIEnv* env, jobject buffer) { - if (buffer == nullptr) { - return nullptr; - } - - jint position; - jint limit; - jint elementSizeShift; - jlong pointer; - pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift); - if (pointer == 0) { - jniThrowException(mEnv, "java/lang/IllegalArgumentException", - "Must use a native order direct Buffer"); - return nullptr; - } - pointer += position << elementSizeShift; - return reinterpret_cast<void*>(pointer); - } - - static void releasePointer(JNIEnv* env, jarray array, void* data, jboolean commit) { - env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT); - } - - static void* getPointer(JNIEnv* env, jobject buffer, jarray* array, jint* remaining, - jint* offset) { - jint position; - jint limit; - jint elementSizeShift; - - jlong pointer; - pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift); - *remaining = (limit - position) << elementSizeShift; - if (pointer != 0L) { - *array = nullptr; - pointer += position << elementSizeShift; - return reinterpret_cast<void*>(pointer); - } - - *array = jniGetNioBufferBaseArray(env, buffer); - *offset = jniGetNioBufferBaseArrayOffset(env, buffer); - return nullptr; - } - - /** - * This is a copy of - * static void android_glBufferData__IILjava_nio_Buffer_2I - * from com_google_android_gles_jni_GLImpl.cpp - */ - void* setIndirectData(size_t size) { - jint exception; - const char* exceptionType; - const char* exceptionMessage; - jint bufferOffset = (jint)0; - jint remaining; - void* tempData; - - if (mBuffer) { - tempData = - (void*)getPointer(mEnv, mBuffer, (jarray*)&mArray, &remaining, &bufferOffset); - if (remaining < size) { - exception = 1; - exceptionType = "java/lang/IllegalArgumentException"; - exceptionMessage = "remaining() < size < needed"; - goto exit; - } - } - if (mBuffer && tempData == nullptr) { - mDataBase = (char*)mEnv->GetPrimitiveArrayCritical(mArray, (jboolean*)0); - tempData = (void*)(mDataBase + bufferOffset); - } - return tempData; - exit: - if (mArray) { - releasePointer(mEnv, mArray, (void*)(mDataBase), JNI_FALSE); - } - if (exception) { - jniThrowException(mEnv, exceptionType, exceptionMessage); - } - return nullptr; - } - - JNIEnv* mEnv; - - // Java Buffer data - void* mData; - jobject mBuffer; - - // Indirect Buffer Data - jarray mArray; - char* mDataBase; -}; - namespace android { static jlong make(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject vertexBuffer, @@ -187,9 +33,12 @@ static jlong make(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject verte jfloat right, jfloat bottom) { auto skMeshSpec = sk_ref_sp(reinterpret_cast<SkMeshSpecification*>(meshSpec)); size_t bufferSize = vertexCount * skMeshSpec->stride(); - auto buff = ScopedJavaNioBuffer(env, vertexBuffer, bufferSize, isDirect); + auto buffer = copyJavaNioBufferToVector(env, vertexBuffer, bufferSize, isDirect); + if (env->ExceptionCheck()) { + return 0; + } auto skRect = SkRect::MakeLTRB(left, top, right, bottom); - auto meshPtr = new Mesh(skMeshSpec, mode, buff.data(), bufferSize, vertexCount, vertexOffset, + auto meshPtr = new Mesh(skMeshSpec, mode, std::move(buffer), vertexCount, vertexOffset, std::make_unique<MeshUniformBuilder>(skMeshSpec), skRect); auto [valid, msg] = meshPtr->validate(); if (!valid) { @@ -205,11 +54,17 @@ static jlong makeIndexed(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobjec auto skMeshSpec = sk_ref_sp(reinterpret_cast<SkMeshSpecification*>(meshSpec)); auto vertexBufferSize = vertexCount * skMeshSpec->stride(); auto indexBufferSize = indexCount * gIndexByteSize; - auto vBuf = ScopedJavaNioBuffer(env, vertexBuffer, vertexBufferSize, isVertexDirect); - auto iBuf = ScopedJavaNioBuffer(env, indexBuffer, indexBufferSize, isIndexDirect); + auto vBuf = copyJavaNioBufferToVector(env, vertexBuffer, vertexBufferSize, isVertexDirect); + if (env->ExceptionCheck()) { + return 0; + } + auto iBuf = copyJavaNioBufferToVector(env, indexBuffer, indexBufferSize, isIndexDirect); + if (env->ExceptionCheck()) { + return 0; + } auto skRect = SkRect::MakeLTRB(left, top, right, bottom); - auto meshPtr = new Mesh(skMeshSpec, mode, vBuf.data(), vertexBufferSize, vertexCount, - vertexOffset, iBuf.data(), indexBufferSize, indexCount, indexOffset, + auto meshPtr = new Mesh(skMeshSpec, mode, std::move(vBuf), vertexCount, vertexOffset, + std::move(iBuf), indexCount, indexOffset, std::make_unique<MeshUniformBuilder>(skMeshSpec), skRect); auto [valid, msg] = meshPtr->validate(); if (!valid) { diff --git a/libs/hwui/jni/text/GraphemeBreak.cpp b/libs/hwui/jni/text/GraphemeBreak.cpp new file mode 100644 index 000000000000..55f03bd9f7b1 --- /dev/null +++ b/libs/hwui/jni/text/GraphemeBreak.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "GraphemeBreaker" + +#include <minikin/GraphemeBreak.h> +#include <nativehelper/ScopedPrimitiveArray.h> + +#include "GraphicsJNI.h" + +namespace android { + +static void nIsGraphemeBreak(JNIEnv* env, jclass, jfloatArray advances, jcharArray text, jint start, + jint end, jbooleanArray isGraphemeBreak) { + if (start > end || env->GetArrayLength(advances) < end || + env->GetArrayLength(isGraphemeBreak) < end - start) { + doThrowAIOOBE(env); + } + + if (start == end) { + return; + } + + ScopedFloatArrayRO advancesArray(env, advances); + ScopedCharArrayRO textArray(env, text); + ScopedBooleanArrayRW isGraphemeBreakArray(env, isGraphemeBreak); + + size_t count = end - start; + for (size_t offset = 0; offset < count; ++offset) { + bool isBreak = minikin::GraphemeBreak::isGraphemeBreak(advancesArray.get(), textArray.get(), + start, end, start + offset); + isGraphemeBreakArray[offset] = isBreak ? JNI_TRUE : JNI_FALSE; + } +} + +static const JNINativeMethod gMethods[] = { + {"nIsGraphemeBreak", + "(" + "[F" // advances + "[C" // text + "I" // start + "I" // end + "[Z" // isGraphemeBreak + ")V", + (void*)nIsGraphemeBreak}, +}; + +int register_android_graphics_text_GraphemeBreak(JNIEnv* env) { + return RegisterMethodsOrDie(env, "android/graphics/text/GraphemeBreak", gMethods, + NELEM(gMethods)); +} + +} // namespace android diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index c6f32c2cd387..88f00dc38cb3 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -123,6 +123,21 @@ public final class GnssCapabilities implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface SubHalPowerCapabilityFlags {} + /** The capability is unknown to be supported or not. */ + public static final int CAPABILITY_UNKNOWN = 0; + /** The capability is supported. */ + public static final int CAPABILITY_SUPPORTED = 1; + /** The capability is not supported. */ + public static final int CAPABILITY_UNSUPPORTED = 2; + + /** @hide */ + @IntDef(flag = true, prefix = {"CAPABILITY_"}, value = {CAPABILITY_UNKNOWN, + CAPABILITY_SUPPORTED, + CAPABILITY_UNSUPPORTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface CapabilitySupportType {} + + /** * Returns an empty GnssCapabilities object. * @@ -375,30 +390,25 @@ public final class GnssCapabilities implements Parcelable { } /** - * Returns {@code true} if GNSS chipset supports accumulated delta range, {@code false} - * otherwise. - * - * <p>The value is only known if {@link #isAccumulatedDeltaRangeCapabilityKnown()} is - * true. + * Returns {@link #CAPABILITY_SUPPORTED} if GNSS chipset supports accumulated delta + * range, {@link #CAPABILITY_UNSUPPORTED} if GNSS chipset does not support accumulated + * delta range, and {@link #CAPABILITY_UNKNOWN} if it is unknown, which means GNSS + * chipset may or may not support accumulated delta range. * * <p>The accumulated delta range information can be queried in * {@link android.location.GnssMeasurement#getAccumulatedDeltaRangeState()}, * {@link android.location.GnssMeasurement#getAccumulatedDeltaRangeMeters()}, and * {@link android.location.GnssMeasurement#getAccumulatedDeltaRangeUncertaintyMeters()}. */ - public boolean hasAccumulatedDeltaRange() { + public @CapabilitySupportType int hasAccumulatedDeltaRange() { if (!mIsAdrCapabilityKnown) { - throw new IllegalStateException("Accumulated delta range capability is unknown."); + return CAPABILITY_UNKNOWN; + } + if ((mTopFlags & TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE) != 0) { + return CAPABILITY_SUPPORTED; + } else { + return CAPABILITY_UNSUPPORTED; } - return (mTopFlags & TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE) != 0; - } - - /** - * Returns {@code true} if {@link #hasAccumulatedDeltaRange()} is known, {@code false} - * otherwise. - */ - public boolean isAccumulatedDeltaRangeCapabilityKnown() { - return mIsAdrCapabilityKnown; } /** @@ -597,9 +607,9 @@ public final class GnssCapabilities implements Parcelable { if (hasMeasurementCorrectionsForDriving()) { builder.append("MEASUREMENT_CORRECTIONS_FOR_DRIVING "); } - if (mIsAdrCapabilityKnown && hasAccumulatedDeltaRange()) { + if (hasAccumulatedDeltaRange() == CAPABILITY_SUPPORTED) { builder.append("ACCUMULATED_DELTA_RANGE "); - } else if (!mIsAdrCapabilityKnown) { + } else if (hasAccumulatedDeltaRange() == CAPABILITY_UNKNOWN) { builder.append("ACCUMULATED_DELTA_RANGE(unknown) "); } if (hasMeasurementCorrectionsLosSats()) { @@ -795,19 +805,17 @@ public final class GnssCapabilities implements Parcelable { /** * Sets accumulated delta range capability. */ - public @NonNull Builder setHasAccumulatedDeltaRange(boolean capable) { - mIsAdrCapabilityKnown = true; - mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, - capable); - return this; - } - - /** - * Clears accumulated delta range capability and sets it as unknown. - */ - public @NonNull Builder clearIsAccumulatedDeltaRangeCapabilityKnown() { - mIsAdrCapabilityKnown = false; - mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, false); + public @NonNull Builder setHasAccumulatedDeltaRange(@CapabilitySupportType int capable) { + if (capable == CAPABILITY_UNKNOWN) { + mIsAdrCapabilityKnown = false; + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, false); + } else if (capable == CAPABILITY_SUPPORTED) { + mIsAdrCapabilityKnown = true; + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, true); + } else if (capable == CAPABILITY_UNSUPPORTED) { + mIsAdrCapabilityKnown = true; + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ACCUMULATED_DELTA_RANGE, false); + } return this; } diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java index 9e9012e43111..d70e8b36afdb 100644 --- a/media/java/android/media/projection/MediaProjection.java +++ b/media/java/android/media/projection/MediaProjection.java @@ -191,7 +191,7 @@ public final class MediaProjection { } else { session = ContentRecordingSession.createTaskSession(launchCookie); } - virtualDisplayConfig.setWindowManagerMirroring(true); + virtualDisplayConfig.setWindowManagerMirroringEnabled(true); final DisplayManager dm = mContext.getSystemService(DisplayManager.class); final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this, virtualDisplayConfig.build(), callback, handler, windowContext); diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS index 96532d00831b..2273f816ac60 100644 --- a/media/java/android/media/projection/OWNERS +++ b/media/java/android/media/projection/OWNERS @@ -1,3 +1,4 @@ michaelwr@google.com santoscordon@google.com chaviw@google.com +nmusgrave@google.com diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java index 7e9443b467ef..c39a6dbd17da 100644 --- a/media/java/android/media/tv/tuner/filter/Filter.java +++ b/media/java/android/media/tv/tuner/filter/Filter.java @@ -32,6 +32,7 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.NullPointerException; import java.util.concurrent.Executor; /** @@ -271,7 +272,12 @@ public class Filter implements AutoCloseable { mExecutor.execute(() -> { synchronized (mCallbackLock) { if (mCallback != null) { - mCallback.onFilterStatusChanged(this, status); + try { + mCallback.onFilterStatusChanged(this, status); + } + catch (NullPointerException e) { + Log.d(TAG, "catch exception:" + e); + } } } }); @@ -285,7 +291,12 @@ public class Filter implements AutoCloseable { mExecutor.execute(() -> { synchronized (mCallbackLock) { if (mCallback != null) { - mCallback.onFilterEvent(this, events); + try { + mCallback.onFilterEvent(this, events); + } + catch (NullPointerException e) { + Log.d(TAG, "catch exception:" + e); + } } else { for (FilterEvent event : events) { if (event instanceof MediaEvent) { diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java index ba751027a3e4..65247a1a9efd 100644 --- a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java +++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java @@ -34,7 +34,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public class IptvFrontendSettings extends FrontendSettings { +public final class IptvFrontendSettings extends FrontendSettings { /** @hide */ @IntDef(prefix = "PROTOCOL_", value = {PROTOCOL_UNDEFINED, PROTOCOL_UDP, PROTOCOL_RTP}) @@ -181,14 +181,6 @@ public class IptvFrontendSettings extends FrontendSettings { } /** - * Creates a builder for {@link IptvFrontendSettings}. - */ - @NonNull - public static Builder builder() { - return new Builder(); - } - - /** * Builder for {@link IptvFrontendSettings}. */ public static final class Builder { @@ -202,7 +194,7 @@ public class IptvFrontendSettings extends FrontendSettings { private long mBitrate = 0; private String mContentUrl = ""; - private Builder() { + public Builder() { } /** @@ -309,8 +301,8 @@ public class IptvFrontendSettings extends FrontendSettings { */ @NonNull public IptvFrontendSettings build() { - return new IptvFrontendSettings(mSrcIpAddress, mDstIpAddress, mSrcPort, - mDstPort, mFec, mProtocol, mIgmp, mBitrate, mContentUrl); + return new IptvFrontendSettings(mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, + mFec, mProtocol, mIgmp, mBitrate, mContentUrl); } } diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java index a70af17c9652..12eebee81bd7 100644 --- a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java +++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java @@ -31,7 +31,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public class IptvFrontendSettingsFec { +public final class IptvFrontendSettingsFec { /** @hide */ @IntDef(prefix = "FEC_TYPE_", value = {FEC_TYPE_UNDEFINED, FEC_TYPE_COLUMN, FEC_TYPE_ROW, FEC_TYPE_COLUMN_ROW}) @@ -93,14 +93,6 @@ public class IptvFrontendSettingsFec { } /** - * Creates a builder for {@link IptvFrontendSettingsFec}. - */ - @NonNull - public static Builder builder() { - return new Builder(); - } - - /** * Builder for {@link IptvFrontendSettingsFec}. */ public static final class Builder { @@ -108,7 +100,7 @@ public class IptvFrontendSettingsFec { private int mFecRowNum; private int mFecColNum; - private Builder() { + public Builder() { } /** diff --git a/packages/CarrierDefaultApp/res/values-af/strings.xml b/packages/CarrierDefaultApp/res/values-af/strings.xml index 13ae4dad7727..cb911d8f95da 100644 --- a/packages/CarrierDefaultApp/res/values-af/strings.xml +++ b/packages/CarrierDefaultApp/res/values-af/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Gaan in elk geval deur blaaier voort"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestasiehupstoot"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Verbeter jou 5G-ervaring"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s beveel aan dat jy ’n werkverrigtinghupstootpakket koop. Tik om deur %2$s te koop."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nie nou nie"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Bestuur"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Koop ’n prestasiehupstoot."</string> diff --git a/packages/CarrierDefaultApp/res/values-am/strings.xml b/packages/CarrierDefaultApp/res/values-am/strings.xml index e1f91ceb9cc2..edaa2486a6f5 100644 --- a/packages/CarrierDefaultApp/res/values-am/strings.xml +++ b/packages/CarrierDefaultApp/res/values-am/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ለምሳሌ፣ የመግቢያ ገጹ የሚታየው ድርጅት ላይሆን ይችላል።"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ለማንኛውም በአሳሽ በኩል ይቀጥሉ"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"የአፈጻጸም ጭማሪ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"የእርስዎን የ5ጂ ተሞክሮ ያሻሽሉ"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s የአፈጻጸም መጨመሪያ ዕቅድ መግዛትን ይመክራል። በ%2$s ለመግዛት መታ ያድርጉ።"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"አሁን አይደለም"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"አስተዳድር"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"የአፈጻጸም ጭማሪ ይግዙ።"</string> diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml index c2e5ba80db46..9bc5e459f9ce 100644 --- a/packages/CarrierDefaultApp/res/values-ar/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"على سبيل المثال، قد لا تنتمي صفحة تسجيل الدخول إلى المؤسسة المعروضة."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"المتابعة على أي حال عبر المتصفح"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"تطبيق تعزيز الأداء"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"تحسين تجربة شبكة الجيل الخامس"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"هناك اقتراح من \"%1$s\" لشراء خطة لتعزيز الأداء. انقر للشراء من خلال \"%2$s\"."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"لاحقًا"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"إدارة"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"شراء تطبيق تعزيز الأداء"</string> diff --git a/packages/CarrierDefaultApp/res/values-as/strings.xml b/packages/CarrierDefaultApp/res/values-as/strings.xml index 8881940ff71a..732c52dc6717 100644 --- a/packages/CarrierDefaultApp/res/values-as/strings.xml +++ b/packages/CarrierDefaultApp/res/values-as/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"উদাহৰণস্বৰূপে, আপোনাক দেখুওৱা লগ ইনৰ পৃষ্ঠাটো প্ৰতিষ্ঠানটোৰ নিজা নহ\'বও পাৰে।"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"তথাপিও ব্ৰাউজাৰৰ জৰিয়তে অব্যাহত ৰাখক"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"কাৰ্যক্ষমতা পৰিৱৰ্ধন"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"আপোনাৰ 5G অভিজ্ঞতা উন্নত কৰক"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$sএ এখন কাৰ্যক্ষমতা পৰিৱৰ্ধন অঁচনি ক্ৰয় কৰাৰ চুপাৰিছ কৰে। %2$sৰ জৰিয়তে ক্ৰয় কৰিবলৈ টিপক।"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"এতিয়া নহয়"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"পৰিচালনা কৰক"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"এটা কাৰ্যক্ষমতা পৰিৱৰ্ধন ক্ৰয় কৰক।"</string> diff --git a/packages/CarrierDefaultApp/res/values-az/strings.xml b/packages/CarrierDefaultApp/res/values-az/strings.xml index f64fcb62ae95..05c300f5217b 100644 --- a/packages/CarrierDefaultApp/res/values-az/strings.xml +++ b/packages/CarrierDefaultApp/res/values-az/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Məsələn, giriş səhifəsi göstərilən təşkilata aid olmaya bilər."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Hər bir halda brazuer ilə davam edin"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performans artırması"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G təcrübənizi təkmilləşdirin"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s performans artırma planı almağı tövsiyə edir. %2$s ilə almaq üçün toxunun."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"İndi yox"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"İdarə edin"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Performans artırması alın."</string> diff --git a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml index 5533bfd1d1e2..deeb5c732c69 100644 --- a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml +++ b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko pregledača"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Poboljšanje učinka"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Poboljšajte 5G doživljaj"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s preporučuje kupovinu paketa za poboljšanje performansi. Dodirnite da biste kupili preko %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljaj"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite poboljšanje učinka."</string> diff --git a/packages/CarrierDefaultApp/res/values-be/strings.xml b/packages/CarrierDefaultApp/res/values-be/strings.xml index 0053cdaa70c3..4f820ca296f7 100644 --- a/packages/CarrierDefaultApp/res/values-be/strings.xml +++ b/packages/CarrierDefaultApp/res/values-be/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Усё роўна працягнуць праз браўзер"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Павышэнне прадукцыйнасці"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Пашырце магчымасці 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s рэкамендуе купіць план павышэння прадукцыйнасці. Націсніце, каб купіць праз %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не цяпер"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Кіраваць"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Аплаціце павышэнне прадукцыйнасці."</string> diff --git a/packages/CarrierDefaultApp/res/values-bg/strings.xml b/packages/CarrierDefaultApp/res/values-bg/strings.xml index a37e0a36454e..a32c632e269c 100644 --- a/packages/CarrierDefaultApp/res/values-bg/strings.xml +++ b/packages/CarrierDefaultApp/res/values-bg/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Например страницата за вход може да не принадлежи на показаната организация."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Продължаване през браузър въпреки това"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Увеличаване на ефективността"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Подобряване на практическата работа с 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s препоръчва да купите план за увеличаване на ефективността. Докоснете, за да купите чрез %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сега"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управление"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Купете пакет за увеличаване на ефективността."</string> diff --git a/packages/CarrierDefaultApp/res/values-bn/strings.xml b/packages/CarrierDefaultApp/res/values-bn/strings.xml index f78449c8aa98..ac4fab43dae1 100644 --- a/packages/CarrierDefaultApp/res/values-bn/strings.xml +++ b/packages/CarrierDefaultApp/res/values-bn/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"যেমন, লগ-ইন পৃষ্ঠাটি যে প্রতিষ্ঠানের পৃষ্ঠা বলে দেখানো আছে, আসলে তা নাও হতে পারে৷"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"যাই হোক, ব্রাউজারের মাধ্যমে চালিয়ে যান"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"পারফর্ম্যান্স বুস্ট"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"আপনার 5G অভিজ্ঞতা উন্নত করুন"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s পারফর্ম্যান্স বুস্ট প্ল্যান কেনার সাজেশন দেয়। %2$s-এর মাধ্যমে কিনতে ট্যাপ করুন।"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"এখন নয়"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ম্যানেজ করুন"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"পারফর্ম্যান্স বুস্ট সংক্রান্ত ফিচার কিনুন।"</string> diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml index 7be8e2b9d177..cc59f9dbfdde 100644 --- a/packages/CarrierDefaultApp/res/values-bs/strings.xml +++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko preglednika"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pojačavanje performansi"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Poboljšajte iskustvo s 5G mrežom"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s preporučuje kupovinu paketa za poboljšanje performansi. Dodirnite da kupite koristeći %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite pojačavanje performansi."</string> diff --git a/packages/CarrierDefaultApp/res/values-ca/strings.xml b/packages/CarrierDefaultApp/res/values-ca/strings.xml index 54c9e6ed43f1..ded2263b3c46 100644 --- a/packages/CarrierDefaultApp/res/values-ca/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ca/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continua igualment mitjançant el navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Optimització de rendiment"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Millora l\'experiència 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomana comprar un pla d\'optimització de rendiment. Toca per comprar-lo mitjançant %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ara no"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestiona"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Compra una optimització de rendiment."</string> diff --git a/packages/CarrierDefaultApp/res/values-cs/strings.xml b/packages/CarrierDefaultApp/res/values-cs/strings.xml index 8a09421cd369..d21c500dcae1 100644 --- a/packages/CarrierDefaultApp/res/values-cs/strings.xml +++ b/packages/CarrierDefaultApp/res/values-cs/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Přihlašovací stránka například nemusí patřit zobrazované organizaci."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Přesto pokračovat prostřednictvím prohlížeče"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zvýšení výkonu"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Získejte rychlejší připojení 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s doporučuje zakoupit zvýšení výkonu. Klepnutím ho zakoupíte přes operátora %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Teď ne"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Spravovat"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupte si zvýšení výkonu."</string> diff --git a/packages/CarrierDefaultApp/res/values-da/strings.xml b/packages/CarrierDefaultApp/res/values-da/strings.xml index cd411c917fb6..192036d10b4f 100644 --- a/packages/CarrierDefaultApp/res/values-da/strings.xml +++ b/packages/CarrierDefaultApp/res/values-da/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Det er f.eks. ikke sikkert, at loginsiden tilhører den anførte organisation."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsæt alligevel via browseren"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ydeevneboost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Få en bedre 5G-oplevelse"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s anbefaler, at du køber et abonnement med ydeevneboost. Tryk for at købe via %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ikke nu"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Køb et ydeevneboost."</string> diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml index d20a1e88fcda..0226d9f70ba8 100644 --- a/packages/CarrierDefaultApp/res/values-de/strings.xml +++ b/packages/CarrierDefaultApp/res/values-de/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Trotzdem in einem Browser fortfahren"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Leistungs-Boost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G-Nutzung verbessern"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s empfiehlt den Kauf eines Tarifs mit Leistungs-Boost. Du kannst tippen, um über %2$s einen zu kaufen."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nicht jetzt"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Verwalten"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Leistungs-Boost erwerben."</string> diff --git a/packages/CarrierDefaultApp/res/values-el/strings.xml b/packages/CarrierDefaultApp/res/values-el/strings.xml index 0759011f5f39..96e3eb342e4c 100644 --- a/packages/CarrierDefaultApp/res/values-el/strings.xml +++ b/packages/CarrierDefaultApp/res/values-el/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Για παράδειγμα, η σελίδα σύνδεσης ενδέχεται να μην ανήκει στον οργανισμό που εμφανίζεται."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Συνέχεια ούτως ή άλλως μέσω του προγράμματος περιήγησης"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ενίσχυση απόδοσης"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Βελτιώστε την εμπειρία 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"Το %1$s προτείνει την αγορά ενός προγράμματος ενίσχυσης απόδοσης. Πατήστε για αγορά μέσω %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Όχι τώρα"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Διαχείριση"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Αγοράστε μια ενίσχυση απόδοσης."</string> diff --git a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml index 720dbc7fe7c0..aac44fc876a7 100644 --- a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml +++ b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string> diff --git a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml index 87978ac33372..d8ec2104098c 100644 --- a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml +++ b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml @@ -15,8 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string> + <string name="performance_boost_notification_title" msgid="6091638924925876776">"Improve your app experience"</string> + <string name="performance_boost_notification_detail" msgid="86969987181456032">"Tap to visit %s\'s website and learn more."</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string> diff --git a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml index 720dbc7fe7c0..aac44fc876a7 100644 --- a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml +++ b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string> diff --git a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml index 720dbc7fe7c0..aac44fc876a7 100644 --- a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml +++ b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string> diff --git a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml index 7324a5bcc1f9..87b007f25650 100644 --- a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml +++ b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml @@ -15,8 +15,8 @@ <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Improve your 5G experience"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommends buying a performance boost plan. Tap to buy through %2$s."</string> + <string name="performance_boost_notification_title" msgid="6091638924925876776">"Improve your app experience"</string> + <string name="performance_boost_notification_detail" msgid="86969987181456032">"Tap to visit %s\'s website and learn more."</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string> diff --git a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml index fedf1ac6b54b..1ad775129883 100644 --- a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml +++ b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos desde el navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de rendimiento"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Mejora tu experiencia de 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomienda que compres un plan de aumento de rendimiento. Presiona para comprar mediante %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ahora no"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrar"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Compra un aumento de rendimiento."</string> diff --git a/packages/CarrierDefaultApp/res/values-es/strings.xml b/packages/CarrierDefaultApp/res/values-es/strings.xml index 85642b8d7934..972afa9dc4b0 100644 --- a/packages/CarrierDefaultApp/res/values-es/strings.xml +++ b/packages/CarrierDefaultApp/res/values-es/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de inicio de sesión no pertenezca a la organización mostrada."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos a través del navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Mejora de rendimiento"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Mejora tu experiencia 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomienda comprar un plan de mejora del rendimiento. Toca para comprarlo mediante %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ahora no"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestionar"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar una mejora de rendimiento."</string> diff --git a/packages/CarrierDefaultApp/res/values-et/strings.xml b/packages/CarrierDefaultApp/res/values-et/strings.xml index 769f24001c68..1ac991cf0c85 100644 --- a/packages/CarrierDefaultApp/res/values-et/strings.xml +++ b/packages/CarrierDefaultApp/res/values-et/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Näiteks ei pruugi sisselogimisleht kuuluda kuvatavale organisatsioonile."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Jätka siiski brauseris"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Jõudluse võimendus"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Täiustage oma 5G-kogemust"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s soovitab osta jõudluse võimendusega paketi. Puudutage teenuse %2$s kaudu ostmiseks."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Mitte praegu"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Haldamine"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Ostke jõudluse võimendus."</string> diff --git a/packages/CarrierDefaultApp/res/values-eu/strings.xml b/packages/CarrierDefaultApp/res/values-eu/strings.xml index 7274bce1b492..fedf29d6563e 100644 --- a/packages/CarrierDefaultApp/res/values-eu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-eu/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Adibidez, baliteke saioa hasteko orria adierazitako erakundearena ez izatea."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Jarraitu arakatzailearen bidez, halere"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Errendimendu-hobekuntza"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Hobetu 5G bidezko konexioa"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s zerbitzuak errendimendua hobetzeko kidetza bat erostea gomendatzen du. Sakatu hau %2$s bidez erosteko."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Orain ez"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Kudeatu"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Erosi errendimendu-hobekuntza bat."</string> diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml index 2cbe29793ada..a9ac1570d44e 100644 --- a/packages/CarrierDefaultApp/res/values-fa/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"به عنوان مثال، صفحه ورود به سیستم ممکن است متعلق به سازمان نشان داده شده نباشد."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"درهر صورت ازطریق مرورگر ادامه یابد"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"تقویتکننده عملکرد"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"تجربه نسل پنجم شبکه تلفن همراه را بهبود دهید"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s توصیه میکند طرح تقویت عملکرد خریداری شود. برای خرید ازطریق %2$s، ضربه بزنید."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"اکنون نه"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"مدیریت"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"تقویتکننده عملکرد خریداری کنید."</string> diff --git a/packages/CarrierDefaultApp/res/values-fi/strings.xml b/packages/CarrierDefaultApp/res/values-fi/strings.xml index 1a388cdc52ef..e0bf1e768c54 100644 --- a/packages/CarrierDefaultApp/res/values-fi/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fi/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Kirjautumissivu ei välttämättä kuulu näytetylle organisaatiolle."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Jatka selaimen kautta"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Suorituskykyboosti"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Paranna 5G-kokemusta"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s suosittelee suorituskykyboostipaketin ostamista. Napauta ja tee ostos operaattorilla %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ei nyt"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Muuta"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Osta suorituskykyboosti."</string> diff --git a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml index ad6c794db5f4..a56a4db3adbc 100644 --- a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion pourrait ne pas appartenir à l\'organisation représentée."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans un navigateur"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Optimiseur de performances"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Améliorer votre expérience de la 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommande d\'acheter un forfait d\'amélioration des performances. Touchez pour acheter par l\'intermédiaire de %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Plus tard"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gérer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Achetez un optimiseur de performances."</string> diff --git a/packages/CarrierDefaultApp/res/values-fr/strings.xml b/packages/CarrierDefaultApp/res/values-fr/strings.xml index 92b47bed7065..699d4b330f8c 100644 --- a/packages/CarrierDefaultApp/res/values-fr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fr/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion peut ne pas appartenir à l\'organisation représentée."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans le navigateur"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Boost de performances"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Améliorer votre expérience 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recommande d\'acheter un forfait d\'amélioration des performances. Appuyez pour acheter via %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Pas maintenant"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gérer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Achetez un boost de performances."</string> diff --git a/packages/CarrierDefaultApp/res/values-gl/strings.xml b/packages/CarrierDefaultApp/res/values-gl/strings.xml index 2c1be52bdabd..b252b8c4cb17 100644 --- a/packages/CarrierDefaultApp/res/values-gl/strings.xml +++ b/packages/CarrierDefaultApp/res/values-gl/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, é posible que a páxina de inicio de sesión non pertenza á organización que se mostra."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar igualmente co navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Mellora de rendemento"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Mellora a túa experiencia 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda comprar un plan de mellora do rendemento. Toca para realizar a compra a través de %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora non"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Xestionar"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar unha mellora de rendemento."</string> diff --git a/packages/CarrierDefaultApp/res/values-gu/strings.xml b/packages/CarrierDefaultApp/res/values-gu/strings.xml index af09d1375c10..8f1174a2eebf 100644 --- a/packages/CarrierDefaultApp/res/values-gu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-gu/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ઉદાહરણ તરીકે, લોગિન પૃષ્ઠ બતાવવામાં આવેલી સંસ્થાનું ન પણ હોય."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"તો પણ બ્રાઉઝર મારફતે ચાલુ રાખો"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"પર્ફોર્મન્સ બૂસ્ટ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"તમારા 5G અનુભવને બહેતર બનાવો"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s પર્ફોર્મન્સ બૂસ્ટ પ્લાન ખરીદવાનો સુઝાવ આપે છે. %2$s મારફતે ખરીદવા માટે ટૅપ કરો."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"હમણાં નહીં"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"મેનેજ કરો"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"પર્ફોર્મન્સ બૂસ્ટ ખરીદો."</string> diff --git a/packages/CarrierDefaultApp/res/values-hi/strings.xml b/packages/CarrierDefaultApp/res/values-hi/strings.xml index e51b1a97dffd..52da32280e17 100644 --- a/packages/CarrierDefaultApp/res/values-hi/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hi/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"उदाहरण के लिए, हो सकता है कि लॉगिन पेज दिखाए गए संगठन का ना हो."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ब्राउज़र के ज़रिए किसी भी तरह जारी रखें"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"परफ़ॉर्मेंस बूस्ट"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G का बेहतर अनुभव पाएं"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s, परफ़ॉर्मेंस को बेहतर बनाने वाले प्लान को खरीदने का सुझाव देता है. %2$s से प्लान खरीदने के लिए टैप करें."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"अभी नहीं"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"मैनेज करें"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"कोई परफ़ॉर्मेंस बूस्ट खरीदें."</string> diff --git a/packages/CarrierDefaultApp/res/values-hr/strings.xml b/packages/CarrierDefaultApp/res/values-hr/strings.xml index 5a22ad54d884..1b601231d738 100644 --- a/packages/CarrierDefaultApp/res/values-hr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hr/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi putem preglednika"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Poboljšanje izvedbe"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Poboljšajte svoj 5G doživljaj"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s preporučuje kupnju paketa za poboljšanje izvedbe. Dodirnite da biste kupili putem usluge %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sad"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite poboljšanje izvedbe."</string> diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml index a841cb24dc19..026586b893d1 100644 --- a/packages/CarrierDefaultApp/res/values-hu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Például lehetséges, hogy a bejelentkezési oldal nem a megjelenített szervezethez tartozik."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Folytatás ennek ellenére böngészőn keresztül"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Teljesítménynövelés"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Az 5G-élmény javítása"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"A(z) %1$s teljesítménynövelő csomag vásárlását javasolja. Koppintson a(z) %2$s szolgáltatón keresztüli vásárláshoz."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Most nem"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Kezelés"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Vásároljon teljesítménynövelést."</string> diff --git a/packages/CarrierDefaultApp/res/values-hy/strings.xml b/packages/CarrierDefaultApp/res/values-hy/strings.xml index 49fbece29a8b..dc93d6e012fc 100644 --- a/packages/CarrierDefaultApp/res/values-hy/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hy/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Օրինակ՝ մուտքի էջը կարող է ցուցադրված կազմակերպության էջը չլինել:"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Շարունակել դիտարկիչի միջոցով"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Արտադրողականության բարձրացում"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Բարելավեք 5G-ի օգտագործման ձեր փորձառությունը"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s օպերատորը խորհուրդ է տալիս ձեռք բերել արդյունավետությունը բարձրացնող սակագնային պլան։ Հպեք՝ %2$s-ի միջոցով գնելու համար։"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ոչ հիմա"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Կառավարել"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Բարձրացրեք ցանցի արտադրողականությունը վճարի դիմաց։"</string> diff --git a/packages/CarrierDefaultApp/res/values-in/strings.xml b/packages/CarrierDefaultApp/res/values-in/strings.xml index 170bd76ca4e6..56b8b2ea6deb 100644 --- a/packages/CarrierDefaultApp/res/values-in/strings.xml +++ b/packages/CarrierDefaultApp/res/values-in/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Misalnya, halaman login mungkin bukan milik organisasi yang ditampilkan."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Tetap lanjutkan melalui browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Penguat sinyal"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Tingkatkan pengalaman 5G Anda"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s merekomendasikan pembelian paket penguat sinyal. Ketuk untuk membeli melalui %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Lain kali"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Kelola"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Beli penguat sinyal."</string> diff --git a/packages/CarrierDefaultApp/res/values-is/strings.xml b/packages/CarrierDefaultApp/res/values-is/strings.xml index 8684ee62d626..510d5fdd986c 100644 --- a/packages/CarrierDefaultApp/res/values-is/strings.xml +++ b/packages/CarrierDefaultApp/res/values-is/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Til dæmis getur verið að innskráningarsíðan tilheyri ekki fyrirtækinu sem birtist."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Halda samt áfram í vafra"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Afkastaaukning"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Bættu upplifun þína af 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s mælir með að kaupa áskrift sem eykur afköst. Ýttu til að kaupa í gegnum %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ekki núna"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Stjórna"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kaupa afkastaaukningu."</string> diff --git a/packages/CarrierDefaultApp/res/values-it/strings.xml b/packages/CarrierDefaultApp/res/values-it/strings.xml index ea884571303f..324aa4f7ce3e 100644 --- a/packages/CarrierDefaultApp/res/values-it/strings.xml +++ b/packages/CarrierDefaultApp/res/values-it/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Ad esempio, la pagina di accesso potrebbe non appartenere all\'organizzazione indicata."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continua comunque dal browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento di prestazioni"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Migliora la tua esperienza 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s consiglia l\'acquisto di un piano di miglioramento delle prestazioni. Tocca per acquistare tramite %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Non ora"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestisci"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Acquista un aumento di prestazioni."</string> diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml index c7229ba56418..9e2f31cb77d8 100644 --- a/packages/CarrierDefaultApp/res/values-iw/strings.xml +++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"המשך בכל זאת באמצעות דפדפן"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"שיפור ביצועים"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"שיפור חווית השימוש ב-5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"יש המלצה של %1$s לקנות תוכנית לשיפור הביצועים. אפשר להקיש כדי לקנות דרך %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"לא עכשיו"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ניהול"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"רכישת שיפור ביצועים."</string> diff --git a/packages/CarrierDefaultApp/res/values-ja/strings.xml b/packages/CarrierDefaultApp/res/values-ja/strings.xml index 2fd86c8a805e..833f8a5b1c04 100644 --- a/packages/CarrierDefaultApp/res/values-ja/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ja/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ブラウザから続行"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"パフォーマンス ブースト"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G のエクスペリエンスを改善"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s さんがパフォーマンス ブースト プランの購入をおすすめしています。%2$sまでにタップして購入しましょう。"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"後で"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"パフォーマンス ブーストを購入してください。"</string> diff --git a/packages/CarrierDefaultApp/res/values-ka/strings.xml b/packages/CarrierDefaultApp/res/values-ka/strings.xml index 76f72737a7df..507e0d9fe378 100644 --- a/packages/CarrierDefaultApp/res/values-ka/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ka/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"მაგალითად, სისტემაში შესვლის გვერდი შეიძლება არ ეკუთვნოდეს ნაჩვენებ ორგანიზაციას."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"მაინც ბრაუზერში გაგრძელება"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ეფექტურობის გაძლიერება"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"გააუმჯობესეთ თქვენი 5G გამოცდილება"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s-ის მიერ რეკომენდებულია ეფექტურობის გაძლიერების გეგმის შეძენა. შეეხეთ %2$s-ის დახმარებით შესაძენად."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ახლა არა"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"მართვა"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ეფექტურობის გაძლიერების შეძენა."</string> diff --git a/packages/CarrierDefaultApp/res/values-kk/strings.xml b/packages/CarrierDefaultApp/res/values-kk/strings.xml index 4a895f47e461..32eae44a3fc9 100644 --- a/packages/CarrierDefaultApp/res/values-kk/strings.xml +++ b/packages/CarrierDefaultApp/res/values-kk/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Мысалы, кіру беті көрсетілген ұйымға тиесілі болмауы мүмкін."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Бәрібір браузер арқылы жалғастыру"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Өнімділікті арттыру"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G желісімен жұмысыңызды жақсартыңыз"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s өнімділікті арттыру жоспарын сатып алуды ұсынады. %2$s операторынан сатып алу үшін түртіңіз."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Қазір емес"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Басқару"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Өнімділікті арттыру құралын сатып алыңыз."</string> diff --git a/packages/CarrierDefaultApp/res/values-km/strings.xml b/packages/CarrierDefaultApp/res/values-km/strings.xml index 51a51ff9698f..531226fcfa07 100644 --- a/packages/CarrierDefaultApp/res/values-km/strings.xml +++ b/packages/CarrierDefaultApp/res/values-km/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ឧទាហរណ៍៖ ទំព័រចូលនេះអាចនឹងមិនមែនជាកម្មសិទ្ធិរបស់ស្ថាប័នដែលបានបង្ហាញនេះទេ។"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"យ៉ាងណាក៏ដោយនៅតែបន្តតាមរយៈកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ការបង្កើនប្រតិបត្តិការ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"កែលម្អបទពិសោធន៍ប្រើ 5G របស់អ្នក"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ណែនាំឱ្យទិញផែនការជំរុញប្រតិបត្តិការ។ ចុចដើម្បីទិញតាមរយៈ %2$s។"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"កុំទាន់"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"គ្រប់គ្រង"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ទិញការបង្កើនប្រតិបត្តិការ។"</string> diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml index c97d6f011e0b..4335d0c8285f 100644 --- a/packages/CarrierDefaultApp/res/values-kn/strings.xml +++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ಉದಾಹರಣೆಗೆ, ಲಾಗಿನ್ ಪುಟವು ತೋರಿಸಲಾಗಿರುವ ಸಂಸ್ಥೆಗೆ ಸಂಬಂಧಿಸಿಲ್ಲದಿರಬಹುದು."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ಪರವಾಗಿಲ್ಲ, ಬ್ರೌಸರ್ ಮೂಲಕ ಮುಂದುವರಿಸಿ"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ಕಾರ್ಯಕ್ಷಮತೆ ಬೂಸ್ಟ್"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"ನಿಮ್ಮ 5G ಅನುಭವವನ್ನು ಸುಧಾರಿಸಿ"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಹೆಚ್ಚಿಸುವ ಪ್ಲಾನ್ ಅನ್ನು ಖರೀದಿಸಲು %1$s ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ. %2$s ಮೂಲಕ ಖರೀದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ಈಗ ಬೇಡ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ನಿರ್ವಹಿಸಿ"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ಕಾರ್ಯಕ್ಷಮತೆ ಬೂಸ್ಟ್ ಅನ್ನು ಖರೀದಿಸಿ."</string> diff --git a/packages/CarrierDefaultApp/res/values-ko/strings.xml b/packages/CarrierDefaultApp/res/values-ko/strings.xml index 395627da1571..3bb5628a680c 100644 --- a/packages/CarrierDefaultApp/res/values-ko/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ko/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"브라우저를 통해 계속하기"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"성능 향상"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G 사용 환경 개선"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s에서 성능 향상 계획 구매를 추천합니다. %2$s을(를) 통해 구매하려면 탭하세요."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"나중에"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"관리"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"성능 향상 구매"</string> diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml index b3970e394b42..07bb61844531 100644 --- a/packages/CarrierDefaultApp/res/values-ky/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, аккаунтка кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Баары бир серепчи аркылуу улантуу"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Иштин майнаптуулугун жогорулатуу"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G менен оңой иштеңиз"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s майнаптуулугун жогорулата турган тарифтик планды сатып алууну сунуштайт. %2$s аркылуу сатып алуу үчүн таптаңыз."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Азыр эмес"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Тескөө"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Иштин майнаптуулугун жогорулатууну сатып алыңыз."</string> diff --git a/packages/CarrierDefaultApp/res/values-lo/strings.xml b/packages/CarrierDefaultApp/res/values-lo/strings.xml index 70d88885008c..480a7ce78751 100644 --- a/packages/CarrierDefaultApp/res/values-lo/strings.xml +++ b/packages/CarrierDefaultApp/res/values-lo/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ຕົວຢ່າງ, ໜ້າເຂົ້າສູ່ລະບົບອາດຈະບໍ່ແມ່ນຂອງອົງກອນທີ່ປາກົດ."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ດຳເນີນການຕໍ່ຜ່ານໂປຣແກຣມທ່ອງເວັບ"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ເລັ່ງປະສິດທິພາບ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"ປັບປຸງປະສົບການ 5G ຂອງທ່ານ"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ແນະນຳໃຫ້ຊື້ແຜນການເລັ່ງປະສິດທິພາບ. ແຕະເພື່ອຊື້ຜ່ານ %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ບໍ່ຟ້າວເທື່ອ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ຈັດການ"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ຊື້ການເລັ່ງປະສິດທິພາບ."</string> diff --git a/packages/CarrierDefaultApp/res/values-lt/strings.xml b/packages/CarrierDefaultApp/res/values-lt/strings.xml index 80684169317a..1f4a4339471b 100644 --- a/packages/CarrierDefaultApp/res/values-lt/strings.xml +++ b/packages/CarrierDefaultApp/res/values-lt/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Vis tiek tęsti naudojant naršyklę"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Našumo pagerinimas"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Pagerinkite 5G ryšį"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"„%1$s“ rekomenduoja įsigyti našumo pagerinimo planą. Palieskite, kad įsigytumėte naudodamiesi „%2$s“ paslaugomis."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne dabar"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Tvarkyti"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Įsigykite našumo pagerinimo paslaugą."</string> diff --git a/packages/CarrierDefaultApp/res/values-lv/strings.xml b/packages/CarrierDefaultApp/res/values-lv/strings.xml index 1fefe92669b1..2fd983775444 100644 --- a/packages/CarrierDefaultApp/res/values-lv/strings.xml +++ b/packages/CarrierDefaultApp/res/values-lv/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Piemēram, pieteikšanās lapa, iespējams, nepieder norādītajai organizācijai."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Tomēr turpināt, izmantojot pārlūkprogrammu"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Veiktspējas uzlabojums"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Uzlabojiet 5G iespējas"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s iesaka iegādāties veiktspējas uzlabošanas plānu. Pieskarieties, lai to iegādātos no %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Vēlāk"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Pārvaldīt"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Iegādājieties veiktspējas uzlabojumu."</string> diff --git a/packages/CarrierDefaultApp/res/values-mk/strings.xml b/packages/CarrierDefaultApp/res/values-mk/strings.xml index 425edfc493e1..6eca2b50a4ba 100644 --- a/packages/CarrierDefaultApp/res/values-mk/strings.xml +++ b/packages/CarrierDefaultApp/res/values-mk/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"На пример, страницата за најавување може да не припаѓа на прикажаната организација."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Сепак продолжи преку прелистувач"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Засилување на изведбата"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Подобрете го вашето доживување со 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s препорачува да купите пакет за засилување на изведбата. Допрете за да купите преку %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сега"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управувајте"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Купете засилување на изведбата."</string> diff --git a/packages/CarrierDefaultApp/res/values-ml/strings.xml b/packages/CarrierDefaultApp/res/values-ml/strings.xml index f2584118516d..2577a144b247 100644 --- a/packages/CarrierDefaultApp/res/values-ml/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ml/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ഉദാഹരണത്തിന്, കാണിച്ചിരിക്കുന്ന ഓർഗനൈസേഷന്റേതായിരിക്കില്ല ലോഗിൻ പേജ്."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"എന്തായാലും ബ്രൗസർ വഴി തുടരുക"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"പ്രകടന ബൂസ്റ്റ്"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"നിങ്ങളുടെ 5G അനുഭവം മെച്ചപ്പെടുത്തുക"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"പ്രകടന ബൂസ്റ്റ് പ്ലാൻ വാങ്ങാൻ %1$s നിർദ്ദേശിക്കുന്നു. %2$s വഴി വാങ്ങാൻ ടാപ്പ് ചെയ്യുക."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ഇപ്പോൾ വേണ്ട"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"മാനേജ് ചെയ്യുക"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"പ്രകടന ബൂസ്റ്റ് വാങ്ങൂ."</string> diff --git a/packages/CarrierDefaultApp/res/values-mn/strings.xml b/packages/CarrierDefaultApp/res/values-mn/strings.xml index 12e17194ffae..f0fc546cacb4 100644 --- a/packages/CarrierDefaultApp/res/values-mn/strings.xml +++ b/packages/CarrierDefaultApp/res/values-mn/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Жишээлбэл нэвтрэх хуудас нь харагдаж буй байгууллагынх биш байж болно."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Ямар ч тохиолдолд хөтчөөр үргэлжлүүлэх"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Гүйцэтгэлийн идэвхжүүлэлт"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G-н хэрэглээгээ сайжруулах"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s гүйцэтгэл нэмэгдүүлэх багцыг худалдаж авахыг зөвлөж байна. %2$s-р дамжуулан худалдан авах бол товшино уу."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Одоо биш"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Удирдах"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Гүйцэтгэлийн идэвхжүүлэлтийг худалдаж аваарай."</string> diff --git a/packages/CarrierDefaultApp/res/values-mr/strings.xml b/packages/CarrierDefaultApp/res/values-mr/strings.xml index a48c60518be1..75cbb1be3e6a 100644 --- a/packages/CarrierDefaultApp/res/values-mr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-mr/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणार्थ, लॉग इन पृष्ठ दर्शवलेल्या संस्थेच्या मालकीचे नसू शकते."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"तरीही ब्राउझरद्वारे सुरू ठेवा"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"परफॉर्मन्स बूस्ट"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"तुमच्या 5G अनुभवामध्ये सुधारणा करा"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s हे परफॉर्मन्स बूस्ट प्लॅन खरेदी करण्याची शिफारस करते. %2$s वरून खरेदी करण्यासाठी टॅप करा."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"आता नको"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"व्यवस्थापित करा"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"परफॉर्मन्स बूस्ट खरेदी करा."</string> diff --git a/packages/CarrierDefaultApp/res/values-ms/strings.xml b/packages/CarrierDefaultApp/res/values-ms/strings.xml index 85651f42b4b3..14842335e668 100644 --- a/packages/CarrierDefaultApp/res/values-ms/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ms/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Teruskan juga melalui penyemak imbas"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Peningkatan prestasi"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Tingkatkan pengalaman 5G anda"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s mengesyorkan pembelian pelan peningkatan prestasi. Ketik untuk membeli melalui %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Bukan sekarang"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Urus"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Beli perangsang prestasi."</string> diff --git a/packages/CarrierDefaultApp/res/values-my/strings.xml b/packages/CarrierDefaultApp/res/values-my/strings.xml index 34c54b9ea835..e7a860e30ab5 100644 --- a/packages/CarrierDefaultApp/res/values-my/strings.xml +++ b/packages/CarrierDefaultApp/res/values-my/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ဥပမာ− ဝင်ရောက်ရန် စာမျက်နှာသည် ပြသထားသည့် အဖွဲ့အစည်းနှင့် သက်ဆိုင်မှုမရှိခြင်း ဖြစ်နိုင်ပါသည်။"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"မည်သို့ပင်ဖြစ်စေ ဘရောက်ဇာမှတစ်ဆင့် ရှေ့ဆက်ရန်"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"စွမ်းဆောင်ရည် မြှင့်တင်အက်ပ်"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G အသုံးပြုမှု ပိုမိုကောင်းမွန်စေခြင်း"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s သည် စွမ်းဆောင်ရည်မြှင့်တင်သော အစီအစဉ်ဝယ်ရန် အကြံပြုပါသည်။ %2$s မှတစ်ဆင့် ဝယ်ရန် တို့ပါ။"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ယခုမလုပ်ပါ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"စီမံရန်"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"စွမ်းဆောင်ရည် မြှင့်တင်အက်ပ် ဝယ်ယူရန်။"</string> diff --git a/packages/CarrierDefaultApp/res/values-nb/strings.xml b/packages/CarrierDefaultApp/res/values-nb/strings.xml index b30e3d9783fe..f0d0d7e95256 100644 --- a/packages/CarrierDefaultApp/res/values-nb/strings.xml +++ b/packages/CarrierDefaultApp/res/values-nb/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Det er for eksempel mulig at påloggingssiden ikke tilhører organisasjonen som vises."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsett likevel via nettleseren"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Bedre ytelse"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Få en bedre 5G-opplevelse"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s anbefaler at du kjøper et abonnement for bedre ytelse. Trykk for å kjøpe via %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ikke nå"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kjøp bedre ytelse."</string> diff --git a/packages/CarrierDefaultApp/res/values-ne/strings.xml b/packages/CarrierDefaultApp/res/values-ne/strings.xml index 4dccdb91f209..f2b0f6efd220 100644 --- a/packages/CarrierDefaultApp/res/values-ne/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ne/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणका लागि, लग इन पृष्ठ देखाइएको संस्थाको नहुन सक्छ।"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"जे भए पनि ब्राउजर मार्फत जारी राख्नुहोस्"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"पर्फर्मेन्स बुस्ट"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G प्रयोग गर्दा अझ राम्रो सुविधा पाउनुहोस्"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ले पर्फर्मेन्स बुस्ट योजना खरिद गर्न सिफारिस गर्छ। %2$s मार्फत खरिद गर्न ट्याप गर्नुहोस्।"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"अहिले होइन"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"व्यवस्थापन गर्नुहोस्"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"पर्फर्मेन्स बुस्ट किन्नुहोस्।"</string> diff --git a/packages/CarrierDefaultApp/res/values-nl/strings.xml b/packages/CarrierDefaultApp/res/values-nl/strings.xml index 6a4642c618dd..f8ff38ad035a 100644 --- a/packages/CarrierDefaultApp/res/values-nl/strings.xml +++ b/packages/CarrierDefaultApp/res/values-nl/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Zo hoort de weergegeven inlogpagina misschien niet bij de weergegeven organisatie."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Toch doorgaan via browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestatieboost"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Verbeter je 5G-functionaliteit"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s beveelt je aan een prestatieboostabonnement te kopen. Tik om er een te kopen via %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Niet nu"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Beheren"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Koop een prestatieboost."</string> diff --git a/packages/CarrierDefaultApp/res/values-or/strings.xml b/packages/CarrierDefaultApp/res/values-or/strings.xml index f7349f9e68a7..bbe6f25c2b34 100644 --- a/packages/CarrierDefaultApp/res/values-or/strings.xml +++ b/packages/CarrierDefaultApp/res/values-or/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ଉଦାହରଣସ୍ୱରୂପ, ଲଗଇନ୍ ପୃଷ୍ଠା ଦେଖାଯାଇଥିବା ସଂସ୍ଥାର ହୋଇନଥାଇପାରେ।"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ବ୍ରାଉଜର୍ ଜରିଆରେ ଯେମିତିବି ହେଉ ଜାରି ରଖନ୍ତୁ"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ପରଫରମାନ୍ସ ବୁଷ୍ଟ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"ଆପଣଙ୍କ 5G ଅନୁଭୂତିକୁ ଉନ୍ନତ କରନ୍ତୁ"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ଏକ ପରଫରମାନ୍ସ ବୁଷ୍ଟ ପ୍ଲାନ କିଣିବା ପାଇଁ ସୁପାରିଶ କରେ। %2$s ମାଧ୍ୟମରେ କିଣିବା ପାଇଁ ଟାପ କରନ୍ତୁ।"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ଏକ ପରଫରମାନ୍ସ ବୁଷ୍ଟ କିଣନ୍ତୁ।"</string> diff --git a/packages/CarrierDefaultApp/res/values-pa/strings.xml b/packages/CarrierDefaultApp/res/values-pa/strings.xml index 540a54cc267e..811eca91280f 100644 --- a/packages/CarrierDefaultApp/res/values-pa/strings.xml +++ b/packages/CarrierDefaultApp/res/values-pa/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ਉਦਾਹਰਣ ਵੱਜੋਂ, ਲੌਗ-ਇਨ ਪੰਨਾ ਦਿਖਾਈ ਗਈ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਨਹੀਂ ਹੋ ਸਕਦਾ ਹੈ।"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ਬ੍ਰਾਊਜ਼ਰ ਰਾਹੀਂ ਫਿਰ ਵੀ ਜਾਰੀ ਰੱਖੋ"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"ਕਾਰਗੁਜ਼ਾਰੀ ਬੂਸਟ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"ਆਪਣਾ 5G ਅਨੁਭਵ ਬਿਹਤਰ ਬਣਾਓ"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ਵੱਲੋਂ ਕਾਰਗੁਜ਼ਾਰੀ ਬੂਸਟ ਪਲਾਨ ਖਰੀਦਣ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। %2$s ਰਾਹੀਂ ਖਰੀਦਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ਹੁਣੇ ਨਹੀਂ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ਕਾਰਗੁਜ਼ਾਰੀ ਬੂਸਟ ਖਰੀਦੋ।"</string> diff --git a/packages/CarrierDefaultApp/res/values-pl/strings.xml b/packages/CarrierDefaultApp/res/values-pl/strings.xml index de957a934d5e..3cd32972ad3e 100644 --- a/packages/CarrierDefaultApp/res/values-pl/strings.xml +++ b/packages/CarrierDefaultApp/res/values-pl/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Na przykład strona logowania może nie należeć do wyświetlanej organizacji."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Kontynuuj mimo to w przeglądarce"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zwiększenie wydajności"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Lepiej wykorzystaj potencjał 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"Operator %1$s zaleca zakup abonamentu o zwiększonej wydajności. Kliknij, aby kupić u operatora %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nie teraz"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Zarządzaj"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kup wzmocnienie wydajności"</string> diff --git a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml index 4a144be2a214..85f049d11399 100644 --- a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml +++ b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de performance"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Melhore sua experiência 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda a compra de um plano para aumento de desempenho. Toque para comprar em %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerenciar"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar um aumento de performance."</string> diff --git a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml index 56e0c2d70e55..981cc5f3eaf6 100644 --- a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml +++ b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de início de sessão pode não pertencer à entidade apresentada."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim através do navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento do desempenho"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Melhore a sua experiência 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda comprar um plano de melhoria do desempenho. Toque para comprar através do %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerir"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Compre um aumento do desempenho."</string> diff --git a/packages/CarrierDefaultApp/res/values-pt/strings.xml b/packages/CarrierDefaultApp/res/values-pt/strings.xml index 4a144be2a214..85f049d11399 100644 --- a/packages/CarrierDefaultApp/res/values-pt/strings.xml +++ b/packages/CarrierDefaultApp/res/values-pt/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de performance"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Melhore sua experiência 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomenda a compra de um plano para aumento de desempenho. Toque para comprar em %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerenciar"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar um aumento de performance."</string> diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml index f8611379188c..287be5ae4b8b 100644 --- a/packages/CarrierDefaultApp/res/values-ro/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Continuă oricum prin browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Boost de performanță"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Îmbunătățește-ți experiența cu tehnologia 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s recomandă cumpărarea unui plan pentru îmbunătățirea performanței. Atinge pentru a cumpăra de la %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nu acum"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestionează"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Achiziționează un boost de performanță."</string> diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml index f0bff17dbaef..fd1328a3e25e 100644 --- a/packages/CarrierDefaultApp/res/values-ru/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Например, страница входа в аккаунт может быть фиктивной."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Продолжить в браузере"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Повышение производительности"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Сделайте работу с 5G удобнее"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"\"%1$s\" рекомендует купить тарифный план, повышающий производительность. Чтобы приобрести тариф у оператора \"%2$s\", коснитесь экрана."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сейчас"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Настроить"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Повысьте производительность сети за плату."</string> diff --git a/packages/CarrierDefaultApp/res/values-si/strings.xml b/packages/CarrierDefaultApp/res/values-si/strings.xml index 166af5a86a7c..a1cd21d4a6e3 100644 --- a/packages/CarrierDefaultApp/res/values-si/strings.xml +++ b/packages/CarrierDefaultApp/res/values-si/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"උදාහරණයක් ලෙස, පුරනය වන පිටුව පෙන්වා ඇති සංවිධානයට අයිති නැති විය හැක."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"කෙසේ වුවත් බ්රවුසරය හරහා ඉදිරියට යන්න"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"කාර්ය සාධනය ඉහළ නැංවීම"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"ඔබේ 5G අත්දැකීම වැඩි දියුණු කරන්න"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s කාර්ය සාධනය වැඩි කිරීමේ සැලසුමක් මිල දී ගැනීම නිර්දේශ කරයි. %2$s හරහා මිල දී ගැනීමට තට්ටු කරන්න."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"දැන් නොවේ"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"කළමනාකරණය කරන්න"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"කාර්ය සාධනය ඉහළ නැංවීමක් මිල දී ගන්න."</string> diff --git a/packages/CarrierDefaultApp/res/values-sk/strings.xml b/packages/CarrierDefaultApp/res/values-sk/strings.xml index a58bd06491c5..265506547d08 100644 --- a/packages/CarrierDefaultApp/res/values-sk/strings.xml +++ b/packages/CarrierDefaultApp/res/values-sk/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Napríklad prihlasovacia stránka nemusí patriť uvedenej organizácii."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Pokračovať pomocou prehliadača"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zvýšenie výkonu"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Zlepšite svoje prostredie 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s odporúča zakúpiť tarifu na zvýšenie výkonnosti. Klepnutím kúpte cez %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Teraz nie"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Spravovať"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kúpte si zvýšenie výkonu."</string> diff --git a/packages/CarrierDefaultApp/res/values-sl/strings.xml b/packages/CarrierDefaultApp/res/values-sl/strings.xml index 3c1fd3ec80f4..32c26599206b 100644 --- a/packages/CarrierDefaultApp/res/values-sl/strings.xml +++ b/packages/CarrierDefaultApp/res/values-sl/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Vseeno nadaljuj v brskalniku"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ojačevalnik zmogljivosti"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Izboljšajte izkušnjo omrežja 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s priporoča nakup paketa ojačevalnika zmogljivosti. Dotaknite se za nakup prek »%2$s«."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne zdaj"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljanje"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite ojačevalnik zmogljivosti."</string> diff --git a/packages/CarrierDefaultApp/res/values-sq/strings.xml b/packages/CarrierDefaultApp/res/values-sq/strings.xml index 618e33573486..f72af39fcd8e 100644 --- a/packages/CarrierDefaultApp/res/values-sq/strings.xml +++ b/packages/CarrierDefaultApp/res/values-sq/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"për shembull, faqja e identifikimit mund të mos i përkasë organizatës së shfaqur."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Vazhdo gjithsesi nëpërmjet shfletuesit"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Përforcimi i performancës"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Përmirëso përvojën tënde 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s rekomandon blerjen e një plani të përforcimit të performancës. Trokit për të blerë nëpërmjet %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Jo tani"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Menaxho"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Bli një paketë përforcimi të performancës."</string> diff --git a/packages/CarrierDefaultApp/res/values-sr/strings.xml b/packages/CarrierDefaultApp/res/values-sr/strings.xml index d28bacca1a07..466e38cffa52 100644 --- a/packages/CarrierDefaultApp/res/values-sr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-sr/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"На пример, страница за пријављивање можда не припада приказаној организацији."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Ипак настави преко прегледача"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Побољшање учинка"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Побољшајте 5G доживљај"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s препоручује куповину пакета за побољшање перформанси. Додирните да бисте купили преко %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сада"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управљај"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Купите побољшање учинка."</string> diff --git a/packages/CarrierDefaultApp/res/values-sv/strings.xml b/packages/CarrierDefaultApp/res/values-sv/strings.xml index ac044ec517b9..ff438b3c74a4 100644 --- a/packages/CarrierDefaultApp/res/values-sv/strings.xml +++ b/packages/CarrierDefaultApp/res/values-sv/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Det kan t.ex. hända att inloggningssidan inte tillhör den organisation som visas."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsätt ändå via webbläsaren"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestandahöjning"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Förbättra din 5G-upplevelse"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s rekommenderar att du köper en prenumeration som kan höja prestandan. Tryck för att köpa via %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Inte nu"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Hantera"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Köp en prestandahöjning."</string> diff --git a/packages/CarrierDefaultApp/res/values-sw/strings.xml b/packages/CarrierDefaultApp/res/values-sw/strings.xml index 1c72f30bbc45..17bcc0fca430 100644 --- a/packages/CarrierDefaultApp/res/values-sw/strings.xml +++ b/packages/CarrierDefaultApp/res/values-sw/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Kwa mfano, ukurasa wa kuingia katika akaunti unaweza usiwe unamilikiwa na shirika lililoonyeshwa."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Endelea hata hivyo kupitia kivinjari"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Kuongeza utendaji"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Boresha hali yako ya utumiaji wa 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s anapendekeza ununue mpango wa kuongeza utendaji. Gusa ili ununue kupitia %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Si sasa"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Dhibiti"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Nunua programu ya kuongeza utendaji."</string> diff --git a/packages/CarrierDefaultApp/res/values-ta/strings.xml b/packages/CarrierDefaultApp/res/values-ta/strings.xml index cfc46e869515..3c347e116a25 100644 --- a/packages/CarrierDefaultApp/res/values-ta/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ta/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"எடுத்துக்காட்டாக, உள்நுழைவுப் பக்கமானது காட்டப்படும் அமைப்பிற்குச் சொந்தமானதாக இல்லாமல் இருக்கலாம்."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"பரவாயில்லை, உலாவி வழியாகத் தொடர்க"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"பெர்ஃபார்மென்ஸ் பூஸ்ட்"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"உங்கள் 5G அனுபவத்தை மேம்படுத்துங்கள்"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"செயல்திறன் மேம்பாட்டுத் திட்டத்தை வாங்க %1$s பரிந்துரைக்கிறது. %2$s மூலம் வாங்க தட்டவும்."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"இப்போது வேண்டாம்"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"நிர்வகியுங்கள்"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ஒரு பெர்ஃபார்மென்ஸ் பூஸ்ட்டைப் பர்ச்சேஸ் செய்யுங்கள்."</string> diff --git a/packages/CarrierDefaultApp/res/values-te/strings.xml b/packages/CarrierDefaultApp/res/values-te/strings.xml index f31291e6ae7f..003df39d41d7 100644 --- a/packages/CarrierDefaultApp/res/values-te/strings.xml +++ b/packages/CarrierDefaultApp/res/values-te/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ఉదాహరణకు, లాగిన్ పేజీ చూపిన సంస్థకు చెందినది కాకపోవచ్చు."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ఏదేమైనా బ్రౌజర్ ద్వారా కొనసాగించండి"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"పనితీరు బూస్ట్"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"మీ 5G అనుభవాన్ని మెరుగుపరుచుకోండి"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"పనితీరును బూస్ట్ చేసే ప్లాన్ను కొనుగోలు చేయమని %1$s సిఫార్సు చేస్తున్నారు. %2$s ద్వారా కొనుగోలు చేయడానికి ట్యాప్ చేయండి."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ఇప్పుడు కాదు"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"మేనేజ్ చేయండి"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"పనితీరు బూస్ట్ను కొనుగోలు చేయండి."</string> diff --git a/packages/CarrierDefaultApp/res/values-th/strings.xml b/packages/CarrierDefaultApp/res/values-th/strings.xml index f20346e5f399..16705d453110 100644 --- a/packages/CarrierDefaultApp/res/values-th/strings.xml +++ b/packages/CarrierDefaultApp/res/values-th/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"ดำเนินการต่อผ่านเบราว์เซอร์"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"การเพิ่มประสิทธิภาพ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"ปรับปรุงประสบการณ์การใช้งาน 5G ของคุณ"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s แนะนำให้ซื้อแพ็กเกจเพิ่มประสิทธิภาพ แตะเพื่อซื้อผ่าน %2$s"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ไว้ทีหลัง"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"จัดการ"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"ซื้อการเพิ่มประสิทธิภาพ"</string> diff --git a/packages/CarrierDefaultApp/res/values-tl/strings.xml b/packages/CarrierDefaultApp/res/values-tl/strings.xml index 9e8029aeaf3d..28cd237d8cc1 100644 --- a/packages/CarrierDefaultApp/res/values-tl/strings.xml +++ b/packages/CarrierDefaultApp/res/values-tl/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Halimbawa, maaaring hindi pag-aari ng ipinapakitang organisasyon ang page ng login."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Magpatuloy pa rin sa pamamagitan ng browser"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pag-boost ng performance"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Pagandahin ang iyong karanasan sa 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"Inirerekomenda ng %1$s na bumili ng plan sa performance boost. I-tap para bumili sa pamamagitan ng %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Huwag muna"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Pamahalaan"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Bumili ng pang-boost ng performance."</string> diff --git a/packages/CarrierDefaultApp/res/values-tr/strings.xml b/packages/CarrierDefaultApp/res/values-tr/strings.xml index c8fb73b42da2..d35db1de4c97 100644 --- a/packages/CarrierDefaultApp/res/values-tr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-tr/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Örneğin, giriş sayfası, gösterilen kuruluşa ait olmayabilir."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Yine de tarayıcıyla devam et"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performans artışı"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G deneyiminizi iyileştirin"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s, performans artırma planı satın almanızı öneriyor. %2$s aracılığıyla satın almak için dokunun."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Şimdi değil"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Yönet"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Performans artışı satın alın."</string> diff --git a/packages/CarrierDefaultApp/res/values-uk/strings.xml b/packages/CarrierDefaultApp/res/values-uk/strings.xml index 9927ea05bb3f..5d6e34a45bfa 100644 --- a/packages/CarrierDefaultApp/res/values-uk/strings.xml +++ b/packages/CarrierDefaultApp/res/values-uk/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Наприклад, сторінка входу може не належати вказаній організації."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Усе одно продовжити у веб-переглядачі"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Підвищення продуктивності"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Покращте продуктивність свого з’єднання 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s рекомендує придбати тарифний план для підвищення продуктивності. Натисніть, щоб придбати через оператора %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не зараз"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Керувати"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Придбайте підвищення продуктивності."</string> diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml index 681998bbecbd..466b6c85a27a 100644 --- a/packages/CarrierDefaultApp/res/values-ur/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"مثال کے طور پر ہو سکتا ہے کہ لاگ ان صفحہ دکھائی گئی تنظیم سے تعلق نہ رکھتا ہو۔"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"پرفارمینس بوسٹ"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"اپنے 5G تجربے کو بہتر بنائیں"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s ایک پرفارمنس بوسٹ پلان کی تجویز کرتا ہے۔ %2$s استعمال کر کے خریدنے کے لیے تھپتھپائیں۔"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ابھی نہیں"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"نظم کریں"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"پرفارمینس بوسٹ خریدیں۔"</string> diff --git a/packages/CarrierDefaultApp/res/values-uz/strings.xml b/packages/CarrierDefaultApp/res/values-uz/strings.xml index 47006f680e29..82da958c63aa 100644 --- a/packages/CarrierDefaultApp/res/values-uz/strings.xml +++ b/packages/CarrierDefaultApp/res/values-uz/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Masalan, tizimga kirish sahifasi ko‘rsatilgan tashkilotga tegishli bo‘lmasligi mumkin."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Brauzerda davom ettirish"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Unumdorlikni kuchaytirish"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"5G bilan ishlashni qulaylashtiring"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s unumdorlikni oshiradigan tarif rejasini xarid qilishni tavsiya etadi. %2$s orqali xarid qilish uchun bosing."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Hozir emas"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Boshqarish"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Unumdorlikni kuchaytirish xizmatini xarid qiling."</string> diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml index 968b6e19e769..225e07b99468 100644 --- a/packages/CarrierDefaultApp/res/values-vi/strings.xml +++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Ví dụ: trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Vẫn tiếp tục qua trình duyệt"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Tăng hiệu suất"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Cải thiện trải nghiệm sử dụng 5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s đề xuất bạn mua gói tăng cường hiệu suất. Nhấn để mua thông qua %2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Để sau"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Quản lý"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Mua gói tăng hiệu suất."</string> diff --git a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml index 563117f83aab..5be55bc8d5d7 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"例如,登录页面可能并不属于页面上显示的单位。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"仍然通过浏览器继续操作"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"性能提升方案"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"改善 5G 体验"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"%1$s建议购买性能提升计划。点按即可通过%2$s进行购买。"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"以后再说"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"购买一份性能提升方案。"</string> diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml index 7ed0c3c03897..92f53d3cc36a 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"例如,登入頁面可能並不屬於所顯示的機構。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"效能提升服務"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"改善 5G 體驗"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"「%1$s」建議購買效能提升服務計劃。輕按即可透過「%2$s」購買。"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"暫時不要"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"購買效能提升服務。"</string> diff --git a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml index 332ab9c809dd..6cb4b943f1b5 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string> <string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"效能提升方案"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"改善 5G 體驗"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"「%1$s」建議購買效能提升方案,輕觸即可透過「%2$s」購買。"</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"暫時不要"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"購買效能提升方案。"</string> diff --git a/packages/CarrierDefaultApp/res/values-zu/strings.xml b/packages/CarrierDefaultApp/res/values-zu/strings.xml index ae846955bb0d..f8bc50ceb446 100644 --- a/packages/CarrierDefaultApp/res/values-zu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zu/strings.xml @@ -15,8 +15,10 @@ <string name="ssl_error_example" msgid="6188711843183058764">"Isibonelo, ikhasi lokungena ngemvume kungenzeka lingelenhlangano ebonisiwe."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Qhubeka noma kunjalo ngesiphequluli"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"I-boost yokusebenza"</string> - <string name="performance_boost_notification_title" msgid="946857427149305992">"Thuthukisa umuzwa wakho we-5G"</string> - <string name="performance_boost_notification_detail" msgid="362407668982648351">"I-%1$s incoma ukuthenga uhlelo lokuthuthukisa ukusebenza. Thepha ukuze uthenge nge-%2$s."</string> + <!-- no translation found for performance_boost_notification_title (6091638924925876776) --> + <skip /> + <!-- no translation found for performance_boost_notification_detail (86969987181456032) --> + <skip /> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Hhayi manje"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Phatha"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Thenga i-boost yokusebenza."</string> diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml index b8427613d8ce..82e5a7f0682a 100644 --- a/packages/CompanionDeviceManager/res/values/strings.xml +++ b/packages/CompanionDeviceManager/res/values/strings.xml @@ -36,17 +36,19 @@ <!-- Description of the privileges the application will get if associated with the companion device of WATCH profile for singleDevice(type) [CHAR LIMIT=NONE] --> <string name="summary_watch_single_device">The app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, and access these permissions:</string> - <!-- TODO(b/256140614) To replace all glasses related strings with final versions --> <!-- ================= DEVICE_PROFILE_GLASSES ================= --> + <!-- Title of the device association confirmation dialog for glasses. --> + <string name="confirmation_title_glasses">Allow <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to manage <strong><xliff:g id="device_name" example="Glasses">%2$s</xliff:g></strong>?</string> + <!-- The name of the "glasses" device type [CHAR LIMIT=30] --> <string name="profile_name_glasses">glasses</string> <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile (type) [CHAR LIMIT=NONE] --> - <string name="summary_glasses">This app is needed to manage <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string> + <string name="summary_glasses_multi_device">This app is needed to manage <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string> <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile for singleDevice(type) [CHAR LIMIT=NONE] --> - <string name="summary_glasses_single_device">The app is needed to manage <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with these permissions:</string> + <string name="summary_glasses_single_device">This app will be allowed to access these permissions on your phone:</string> <!-- ================= DEVICE_PROFILE_APP_STREAMING ================= --> @@ -81,17 +83,13 @@ <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] --> <string name="helper_summary_computer"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string> - <!-- TODO(b/256140614) To replace all nearby_device_streaming related strings with final versions --> <!-- ================= DEVICE_PROFILE_NEARBY_DEVICE_STREAMING ================= --> <!-- Confirmation for associating an application with a companion device of NEARBY_DEVICE_STREAMING profile (type) [CHAR LIMIT=NONE] --> - <string name="title_nearby_device_streaming">Allow <strong><xliff:g id="app_name" example="NearbyStreamer">%1$s</xliff:g></strong> to perform this action from your phone</string> - - <!-- Title of the helper dialog for NEARBY_DEVICE_STREAMING profile [CHAR LIMIT=30]. --> - <string name="helper_title_nearby_device_streaming">Cross-device services</string> + <string name="title_nearby_device_streaming">Allow <strong><xliff:g id="device_name" example="NearbyStreamer">%1$s</xliff:g></strong> to take this action?</string> <!-- Description of the helper dialog for NEARBY_DEVICE_STREAMING profile. [CHAR LIMIT=NONE] --> - <string name="helper_summary_nearby_device_streaming"><xliff:g id="app_name" example="NearbyStreamerApp">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="NearbyDevice">%2$s</xliff:g> to stream content to nearby devices</string> + <string name="helper_summary_nearby_device_streaming"><xliff:g id="app_name" example="NearbyStreamerApp">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_name" example="NearbyDevice">%2$s</xliff:g> to stream apps and other system features to nearby devices</string> <!-- ================= null profile ================= --> @@ -161,7 +159,7 @@ <string name="permission_app_streaming">Apps</string> <!-- Nearby_device_streaming permission will be granted to the corresponding profile [CHAR LIMIT=45] --> - <string name="permission_nearby_device_streaming">Nearby Device Streaming</string> + <string name="permission_nearby_device_streaming">Streaming</string> <!-- Description of phone permission of corresponding profile [CHAR LIMIT=NONE] --> <string name="permission_phone_summary">Can make and manage phone calls</string> @@ -179,8 +177,7 @@ <string name="permission_calendar_summary">Can access your calendar</string> <!-- Description of microphone permission of corresponding profile [CHAR LIMIT=NONE] --> - <!-- TODO(b/256140614) Need the description for microphone permission --> - <string name="permission_microphone_summary">Can record audio using the microphone</string> + <string name="permission_microphone_summary">Can record audio</string> <!-- Description of nearby devices' permission of corresponding profile [CHAR LIMIT=NONE] --> <string name="permission_nearby_devices_summary">Can find, connect to, and determine the relative position of nearby devices</string> @@ -195,7 +192,6 @@ <string name="permission_storage_summary"></string> <!-- Description of nearby_device_streaming permission of corresponding profile [CHAR LIMIT=NONE] --> - <!-- TODO(b/256140614) Need the description for nearby devices' permission --> - <string name="permission_nearby_device_streaming_summary">Stream content to a nearby device</string> + <string name="permission_nearby_device_streaming_summary">Stream apps and other system features from your phone</string> </resources> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index 918f9c681c5a..8316f9df323f 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -30,6 +30,7 @@ import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService import static com.android.companiondevicemanager.CompanionDeviceResources.MULTI_DEVICES_SUMMARIES; import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TYPES; import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME; +import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME_MULTI; import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICON; import static com.android.companiondevicemanager.CompanionDeviceResources.SUMMARIES; import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES; @@ -571,6 +572,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements final String deviceProfile = mRequest.getDeviceProfile(); final String profileName; + final String profileNameMulti; final Spanned summary; final Drawable profileIcon; final int summaryResourceId; @@ -580,6 +582,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements } profileName = getString(PROFILES_NAME.get(deviceProfile)); + profileNameMulti = getString(PROFILES_NAME_MULTI.get(deviceProfile)); profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile)); summaryResourceId = MULTI_DEVICES_SUMMARIES.get(deviceProfile); @@ -590,7 +593,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements } final Spanned title = getHtmlFromResources( - this, R.string.chooser_title, profileName, appLabel); + this, R.string.chooser_title, profileNameMulti, appLabel); mTitle.setText(title); mSummary.setText(summary); diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java index e3fd3545ca4b..7aed13960b08 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java @@ -59,7 +59,7 @@ final class CompanionDeviceResources { map.put(DEVICE_PROFILE_COMPUTER, R.string.title_computer); map.put(DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, R.string.title_nearby_device_streaming); map.put(DEVICE_PROFILE_WATCH, R.string.confirmation_title); - map.put(DEVICE_PROFILE_GLASSES, R.string.confirmation_title); + map.put(DEVICE_PROFILE_GLASSES, R.string.confirmation_title_glasses); map.put(null, R.string.confirmation_title); TITLES = unmodifiableMap(map); @@ -97,7 +97,7 @@ final class CompanionDeviceResources { static { final Map<String, Integer> map = new ArrayMap<>(); map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch); - map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses); + map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses_multi_device); map.put(null, R.string.summary_generic); MULTI_DEVICES_SUMMARIES = unmodifiableMap(map); @@ -113,6 +113,16 @@ final class CompanionDeviceResources { PROFILES_NAME = unmodifiableMap(map); } + static final Map<String, Integer> PROFILES_NAME_MULTI; + static { + final Map<String, Integer> map = new ArrayMap<>(); + map.put(DEVICE_PROFILE_GLASSES, R.string.profile_name_generic); + map.put(DEVICE_PROFILE_WATCH, R.string.profile_name_watch); + map.put(null, R.string.profile_name_generic); + + PROFILES_NAME_MULTI = unmodifiableMap(map); + } + static final Map<String, Integer> PROFILE_ICON; static { final Map<String, Integer> map = new ArrayMap<>(); @@ -133,7 +143,6 @@ final class CompanionDeviceResources { SUPPORTED_PROFILES = unmodifiableSet(set); } - static final Set<String> SUPPORTED_SELF_MANAGED_PROFILES; static { final Set<String> set = new ArraySet<>(); @@ -145,6 +154,4 @@ final class CompanionDeviceResources { SUPPORTED_SELF_MANAGED_PROFILES = unmodifiableSet(set); } - - } diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java index eae14a6ac175..8f32dbb86d04 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java @@ -21,6 +21,7 @@ import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER; import static android.companion.AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING; import static com.android.companiondevicemanager.Utils.getApplicationIcon; +import static com.android.companiondevicemanager.Utils.getApplicationLabel; import static com.android.companiondevicemanager.Utils.getHtmlFromResources; import android.annotation.Nullable; @@ -105,9 +106,11 @@ public class CompanionVendorHelperDialogFragment extends DialogFragment { final String packageName = request.getPackageName(); final CharSequence displayName = request.getDisplayName(); final int userId = request.getUserId(); + final CharSequence appLabel; try { applicationIcon = getApplicationIcon(getContext(), packageName); + appLabel = getApplicationLabel(getContext(), packageName, userId); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Package u" + userId + "/" + packageName + " not found."); mListener.onShowHelperDialogFailed(); @@ -119,7 +122,7 @@ public class CompanionVendorHelperDialogFragment extends DialogFragment { mAppIcon = view.findViewById(R.id.app_icon); mButton = view.findViewById(R.id.btn_back); - final Spanned title; + final CharSequence title; final Spanned summary; switch (deviceProfile) { @@ -136,8 +139,7 @@ public class CompanionVendorHelperDialogFragment extends DialogFragment { break; case DEVICE_PROFILE_NEARBY_DEVICE_STREAMING: - title = getHtmlFromResources(getContext(), - R.string.helper_title_nearby_device_streaming); + title = appLabel; summary = getHtmlFromResources( getContext(), R.string.helper_summary_nearby_device_streaming, title, displayName); diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp index 00d42bd836b1..28b9bc04a249 100644 --- a/packages/CredentialManager/Android.bp +++ b/packages/CredentialManager/Android.bp @@ -20,6 +20,7 @@ android_app { }, static_libs: [ + "PlatformComposeCore", "androidx.activity_activity-compose", "androidx.appcompat_appcompat", "androidx.compose.animation_animation-core", diff --git a/packages/CredentialManager/res/drawable/ic_other_devices.xml b/packages/CredentialManager/res/drawable/ic_other_devices.xml deleted file mode 100644 index 754648cbca1d..000000000000 --- a/packages/CredentialManager/res/drawable/ic_other_devices.xml +++ /dev/null @@ -1,15 +0,0 @@ -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - tools:ignore="VectorPath" - android:name="vector" - android:width="20dp" - android:height="20dp" - android:viewportWidth="20" - android:viewportHeight="20"> - <path - android:name="path" - android:pathData="M 7.6 4.72 L 7.6 7.6 L 4.72 7.6 L 4.72 4.72 L 7.6 4.72 Z M 9.04 3.28 L 3.28 3.28 L 3.28 9.04 L 9.04 9.04 L 9.04 3.28 Z M 7.6 12.4 L 7.6 15.28 L 4.72 15.28 L 4.72 12.4 L 7.6 12.4 Z M 9.04 10.96 L 3.28 10.96 L 3.28 16.72 L 9.04 16.72 L 9.04 10.96 Z M 15.28 4.72 L 15.28 7.6 L 12.4 7.6 L 12.4 4.72 L 15.28 4.72 Z M 16.72 3.28 L 10.96 3.28 L 10.96 9.04 L 16.72 9.04 L 16.72 3.28 Z M 10.96 10.96 L 12.4 10.96 L 12.4 12.4 L 10.96 12.4 L 10.96 10.96 Z M 12.4 12.4 L 13.84 12.4 L 13.84 13.84 L 12.4 13.84 L 12.4 12.4 Z M 13.84 10.96 L 15.28 10.96 L 15.28 12.4 L 13.84 12.4 L 13.84 10.96 Z M 10.96 13.84 L 12.4 13.84 L 12.4 15.28 L 10.96 15.28 L 10.96 13.84 Z M 12.4 15.28 L 13.84 15.28 L 13.84 16.72 L 12.4 16.72 L 12.4 15.28 Z M 13.84 13.84 L 15.28 13.84 L 15.28 15.28 L 13.84 15.28 L 13.84 13.84 Z M 15.28 12.4 L 16.72 12.4 L 16.72 13.84 L 15.28 13.84 L 15.28 12.4 Z M 15.28 15.28 L 16.72 15.28 L 16.72 16.72 L 15.28 16.72 L 15.28 15.28 Z M 19.6 5.2 L 17.68 5.2 L 17.68 2.32 L 14.8 2.32 L 14.8 0.4 L 19.6 0.4 L 19.6 5.2 Z M 19.6 19.6 L 19.6 14.8 L 17.68 14.8 L 17.68 17.68 L 14.8 17.68 L 14.8 19.6 L 19.6 19.6 Z M 0.4 19.6 L 5.2 19.6 L 5.2 17.68 L 2.32 17.68 L 2.32 14.8 L 0.4 14.8 L 0.4 19.6 Z M 0.4 0.4 L 0.4 5.2 L 2.32 5.2 L 2.32 2.32 L 5.2 2.32 L 5.2 0.4 L 0.4 0.4 Z" - android:fillColor="#000000" - android:strokeWidth="1"/> -</vector>
\ No newline at end of file diff --git a/packages/CredentialManager/res/drawable/ic_other_sign_in.xml b/packages/CredentialManager/res/drawable/ic_other_sign_in.xml deleted file mode 100644 index 81501972d3ba..000000000000 --- a/packages/CredentialManager/res/drawable/ic_other_sign_in.xml +++ /dev/null @@ -1,36 +0,0 @@ -<!-- - ~ 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. - --> - -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - tools:ignore="VectorPath" - android:name="vector" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:name="path" - android:pathData="M 20 19 L 12 19 L 12 21 L 20 21 C 21.1 21 22 20.1 22 19 L 22 5 C 22 3.9 21.1 3 20 3 L 12 3 L 12 5 L 20 5 L 20 19 Z" - android:fillColor="#000" - android:strokeWidth="1"/> - <path - android:name="path_1" - android:pathData="M 12 7 L 10.6 8.4 L 13.2 11 L 8.85 11 C 8.42 9.55 7.09 8.5 5.5 8.5 C 3.57 8.5 2 10.07 2 12 C 2 13.93 3.57 15.5 5.5 15.5 C 7.09 15.5 8.42 14.45 8.85 13 L 13.2 13 L 10.6 15.6 L 12 17 L 17 12 L 12 7 Z M 5.5 13.5 C 4.67 13.5 4 12.83 4 12 C 4 11.17 4.67 10.5 5.5 10.5 C 6.33 10.5 7 11.17 7 12 C 7 12.83 6.33 13.5 5.5 13.5 Z" - android:fillColor="#000" - android:strokeWidth="1"/> -</vector>
\ No newline at end of file diff --git a/packages/CredentialManager/res/drawable/ic_other_sign_in_24.xml b/packages/CredentialManager/res/drawable/ic_other_sign_in_24.xml new file mode 100644 index 000000000000..ce2aeb213cf2 --- /dev/null +++ b/packages/CredentialManager/res/drawable/ic_other_sign_in_24.xml @@ -0,0 +1,30 @@ +<!-- + ~ 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. + --> + +<vector + android:alpha="0.8" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24" + android:width="24dp" + xmlns:android="http://schemas.android.com/apk/res/android" +> +<group> + <clip-path android:pathData="M0,0h24v24h-24z"/> + <path android:fillColor="#444746" android:pathData="M20,19H12V21H20C21.1,21 22,20.1 22,19V5C22,3.9 21.1,3 20,3H12V5H20V19Z"/> + <path android:fillColor="#444746" android:pathData="M12,7L10.6,8.4L13.2,11H8.85C8.42,9.55 7.09,8.5 5.5,8.5C3.57,8.5 2,10.07 2,12C2,13.93 3.57,15.5 5.5,15.5C7.09,15.5 8.42,14.45 8.85,13H13.2L10.6,15.6L12,17L17,12L12,7ZM5.5,13.5C4.67,13.5 4,12.83 4,12C4,11.17 4.67,10.5 5.5,10.5C6.33,10.5 7,11.17 7,12C7,12.83 6.33,13.5 5.5,13.5Z"/> +</group> +</vector>
\ No newline at end of file diff --git a/packages/CredentialManager/res/drawable/ic_passkey.xml b/packages/CredentialManager/res/drawable/ic_passkey.xml deleted file mode 100644 index 041a32164073..000000000000 --- a/packages/CredentialManager/res/drawable/ic_passkey.xml +++ /dev/null @@ -1,16 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="28dp" - android:height="24dp" - android:viewportWidth="28" - android:viewportHeight="24"> - <path - android:pathData="M27.453,13.253C27.453,14.952 26.424,16.411 24.955,17.041L26.21,18.295L24.839,19.666L26.21,21.037L23.305,23.942L22.012,22.65L22.012,17.156C20.385,16.605 19.213,15.066 19.213,13.253C19.213,10.977 21.058,9.133 23.333,9.133C25.609,9.133 27.453,10.977 27.453,13.253ZM25.47,13.254C25.47,14.434 24.514,15.39 23.334,15.39C22.154,15.39 21.197,14.434 21.197,13.254C21.197,12.074 22.154,11.118 23.334,11.118C24.514,11.118 25.47,12.074 25.47,13.254Z" - android:fillColor="#00639B" - android:fillType="evenOdd"/> - <path - android:pathData="M17.85,5.768C17.85,8.953 15.268,11.536 12.083,11.536C8.897,11.536 6.315,8.953 6.315,5.768C6.315,2.582 8.897,0 12.083,0C15.268,0 17.85,2.582 17.85,5.768Z" - android:fillColor="#00639B"/> - <path - android:pathData="M0.547,20.15C0.547,16.32 8.23,14.382 12.083,14.382C13.59,14.382 15.684,14.679 17.674,15.269C18.116,16.454 18.952,17.447 20.022,18.089V23.071H0.547V20.15Z" - android:fillColor="#00639B"/> -</vector> diff --git a/packages/CredentialManager/res/drawable/ic_passkey_24.xml b/packages/CredentialManager/res/drawable/ic_passkey_24.xml new file mode 100644 index 000000000000..a2c4f374caf1 --- /dev/null +++ b/packages/CredentialManager/res/drawable/ic_passkey_24.xml @@ -0,0 +1,28 @@ +<!-- + ~ 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 + android:alpha="0.8" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24" + android:width="24dp" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + <path android:fillColor="#4C463C" android:fillType="evenOdd" android:pathData="M22.18,14.09C22.18,15.364 21.408,16.459 20.306,16.931L21.247,17.872L20.219,18.9L21.247,19.928L19.068,22.107L18.099,21.138L18.099,17.017C16.878,16.604 16,15.45 16,14.09C16,12.383 17.383,11 19.09,11C20.796,11 22.18,12.383 22.18,14.09ZM20.692,14.091C20.692,14.976 19.975,15.693 19.09,15.693C18.205,15.693 17.488,14.976 17.488,14.091C17.488,13.206 18.205,12.488 19.09,12.488C19.975,12.488 20.692,13.206 20.692,14.091Z"/> + <path android:fillColor="#4C463C" android:pathData="M14.978,8.476C14.978,10.865 13.041,12.802 10.652,12.802C8.263,12.802 6.326,10.865 6.326,8.476C6.326,6.087 8.263,4.15 10.652,4.15C13.041,4.15 14.978,6.087 14.978,8.476Z"/> + <path android:fillColor="#4C463C" android:pathData="M2,19.263C2,16.39 7.762,14.937 10.652,14.937C11.782,14.937 13.353,15.16 14.845,15.602C15.177,16.491 15.804,17.236 16.607,17.717V21.454H2V19.263Z"/> +</vector> diff --git a/packages/CredentialManager/res/drawable/ic_password.xml b/packages/CredentialManager/res/drawable/ic_password.xml deleted file mode 100644 index bf3056a115c1..000000000000 --- a/packages/CredentialManager/res/drawable/ic_password.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- - ~ 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. - --> - -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - tools:ignore="VectorPath" - android:name="vector" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:name="path" - android:pathData="M 8.71 10.29 C 8.52 10.1 8.28 10 8 10 L 7.75 10 L 7.75 8.75 C 7.75 7.98 7.48 7.33 6.95 6.8 C 6.42 6.27 5.77 6 5 6 C 4.23 6 3.58 6.27 3.05 6.8 C 2.52 7.33 2.25 7.98 2.25 8.75 L 2.25 10 L 2 10 C 1.72 10 1.48 10.1 1.29 10.29 C 1.1 10.48 1 10.72 1 11 L 1 16 C 1 16.28 1.1 16.52 1.29 16.71 C 1.48 16.9 1.72 17 2 17 L 8 17 C 8.28 17 8.52 16.9 8.71 16.71 C 8.9 16.52 9 16.28 9 16 L 9 11 C 9 10.72 8.9 10.48 8.71 10.29 Z M 6.25 10 L 3.75 10 L 3.75 8.75 C 3.75 8.4 3.87 8.1 4.11 7.86 C 4.35 7.62 4.65 7.5 5 7.5 C 5.35 7.5 5.65 7.62 5.89 7.86 C 6.13 8.1 6.25 8.4 6.25 8.75 L 6.25 10 Z M 10 14 L 23 14 L 23 16 L 10 16 Z M 21.5 9 C 21.102 9 20.721 9.158 20.439 9.439 C 20.158 9.721 20 10.102 20 10.5 C 20 10.898 20.158 11.279 20.439 11.561 C 20.721 11.842 21.102 12 21.5 12 C 21.898 12 22.279 11.842 22.561 11.561 C 22.842 11.279 23 10.898 23 10.5 C 23 10.102 22.842 9.721 22.561 9.439 C 22.279 9.158 21.898 9 21.5 9 Z M 16.5 9 C 16.102 9 15.721 9.158 15.439 9.439 C 15.158 9.721 15 10.102 15 10.5 C 15 10.898 15.158 11.279 15.439 11.561 C 15.721 11.842 16.102 12 16.5 12 C 16.898 12 17.279 11.842 17.561 11.561 C 17.842 11.279 18 10.898 18 10.5 C 18 10.102 17.842 9.721 17.561 9.439 C 17.279 9.158 16.898 9 16.5 9 Z M 11.5 9 C 11.102 9 10.721 9.158 10.439 9.439 C 10.158 9.721 10 10.102 10 10.5 C 10 10.898 10.158 11.279 10.439 11.561 C 10.721 11.842 11.102 12 11.5 12 C 11.898 12 12.279 11.842 12.561 11.561 C 12.842 11.279 13 10.898 13 10.5 C 13 10.102 12.842 9.721 12.561 9.439 C 12.279 9.158 11.898 9 11.5 9 Z" - android:fillColor="#000" - android:strokeWidth="1"/> -</vector>
\ No newline at end of file diff --git a/packages/CredentialManager/res/drawable/ic_password_24.xml b/packages/CredentialManager/res/drawable/ic_password_24.xml new file mode 100644 index 000000000000..8b24e882faf4 --- /dev/null +++ b/packages/CredentialManager/res/drawable/ic_password_24.xml @@ -0,0 +1,34 @@ +<!-- + ~ 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. + --> + +<vector + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:ignore="VectorPath" + android:name="vector" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z"/> + <path android:fillColor="#4C463C" android:pathData="M8.46,10.29C8.27,10.1 8.03,10 7.75,10H7.5V8.75C7.5,7.98 7.23,7.33 6.7,6.8C6.17,6.27 5.52,6 4.75,6C3.98,6 3.33,6.27 2.8,6.8C2.27,7.33 2,7.98 2,8.75V10H1.75C1.47,10 1.23,10.1 1.04,10.29C0.85,10.48 0.75,10.72 0.75,11V16C0.75,16.28 0.85,16.52 1.04,16.71C1.23,16.9 1.47,17 1.75,17H7.75C8.03,17 8.27,16.9 8.46,16.71C8.65,16.52 8.75,16.28 8.75,16V11C8.75,10.72 8.65,10.48 8.46,10.29ZM6,10H3.5V8.75C3.5,8.4 3.62,8.1 3.86,7.86C4.1,7.62 4.4,7.5 4.75,7.5C5.1,7.5 5.4,7.62 5.64,7.86C5.88,8.1 6,8.4 6,8.75V10Z"/> + <path android:fillColor="#4C463C" android:pathData="M23.5,14H10.5V16H23.5V14Z"/> + <path android:fillColor="#4C463C" android:pathData="M22,12C22.828,12 23.5,11.328 23.5,10.5C23.5,9.672 22.828,9 22,9C21.172,9 20.5,9.672 20.5,10.5C20.5,11.328 21.172,12 22,12Z"/> + <path android:fillColor="#4C463C" android:pathData="M17,12C17.828,12 18.5,11.328 18.5,10.5C18.5,9.672 17.828,9 17,9C16.172,9 15.5,9.672 15.5,10.5C15.5,11.328 16.172,12 17,12Z"/> + <path android:fillColor="#4C463C" android:pathData="M12,12C12.828,12 13.5,11.328 13.5,10.5C13.5,9.672 12.828,9 12,9C11.172,9 10.5,9.672 10.5,10.5C10.5,11.328 11.172,12 12,12Z"/> + </group> +</vector>
\ No newline at end of file diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml index 3d32642884d5..f0f040f4a866 100644 --- a/packages/CredentialManager/res/values-af/strings.xml +++ b/packages/CredentialManager/res/values-af/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Maak sigblad toe"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gaan terug na die vorige bladsy"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Maak toe"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gebruik jou gestoorde wagwoordsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gebruik jou gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Kies ’n gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml index 76533e54c94f..730b0b020eeb 100644 --- a/packages/CredentialManager/res/values-am/strings.xml +++ b/packages/CredentialManager/res/values-am/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"ሌሎች የይለፍ ቃል አስተዳዳሪዎች"</string> <string name="close_sheet" msgid="1393792015338908262">"ሉህን ዝጋ"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ወደ ቀዳሚው ገፅ ይመለሱ"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"ዝጋ"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"የተቀመጠ የይለፍ ቁልፍዎን ለ<xliff:g id="APP_NAME">%1$s</xliff:g> ይጠቀሙ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"የተቀመጠ መግቢያዎን ለ<xliff:g id="APP_NAME">%1$s</xliff:g> ይጠቀሙ?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"የተቆለፉ የሚስጥር ቁልፍ አስተዳዳሪዎች"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ለመክፈት መታ ያድርጉ"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"ምንም የመግቢያ ማስረጃ የለም"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> ውስጥ ምንም የመግቢያ መረጃ የለም"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"መግቢያዎችን ያስተዳድሩ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ከሌላ መሣሪያ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"የተለየ መሣሪያ ይጠቀሙ"</string> diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml index c5de5c84316d..666f903514c6 100644 --- a/packages/CredentialManager/res/values-ar/strings.xml +++ b/packages/CredentialManager/res/values-ar/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"خدمات مدراء كلمات المرور الأخرى"</string> <string name="close_sheet" msgid="1393792015338908262">"إغلاق ورقة البيانات"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"العودة إلى الصفحة السابقة"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"إغلاق"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"هل تريد استخدام مفتاح المرور المحفوظ لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"هل تريد استخدام بيانات اعتماد تسجيل الدخول المحفوظة لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"خدمات إدارة كلمات المرور المقفولة"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"انقر لفتح القفل."</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"ما مِن معلومات تسجيل دخول."</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"ليس هناك معلومات تسجيل دخول في <xliff:g id="SOURCE">%1$s</xliff:g>."</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"إداراة عمليات تسجيل الدخول"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"من جهاز آخر"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استخدام جهاز مختلف"</string> diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml index 1ee0a4690aa8..6202de5dec45 100644 --- a/packages/CredentialManager/res/values-as/strings.xml +++ b/packages/CredentialManager/res/values-as/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"শ্বীট বন্ধ কৰক"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"পূৰ্বৱৰ্তী পৃষ্ঠালৈ ঘূৰি যাওক"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"বন্ধ কৰক"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে আপোনাৰ ছেভ হৈ থকা পাছকী ব্যৱহাৰ কৰিবনে?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে আপোনাৰ ছেভ হৈ থকা ছাইন ইন তথ্য ব্যৱহাৰ কৰিবনে?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে ছেভ হৈ থকা এটা ছাইন ইন বাছনি কৰক"</string> diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml index 778b78fcc77c..2481a5cf8d80 100644 --- a/packages/CredentialManager/res/values-az/strings.xml +++ b/packages/CredentialManager/res/values-az/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Səhifəni bağlayın"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Əvvəlki səhifəyə qayıdın"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Bağlayın"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış giriş açarı istifadə edilsin?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış girişdən istifadə edilsin?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış girişi seçin"</string> diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml index e18aed534001..1e7e92e1efc1 100644 --- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Drugi menadžeri lozinki"</string> <string name="close_sheet" msgid="1393792015338908262">"Zatvorite tabelu"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Vratite se na prethodnu stranicu"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Zatvorite"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite da koristite sačuvani pristupni kôd za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite da koristite sačuvane podatke za prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Menadžeri zaključanih lozinki"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dodirnite da biste otključali"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nema podataka za prijavljivanje"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nema podataka za prijavljivanje u: <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljajte prijavljivanjima"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Sa drugog uređaja"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Koristi drugi uređaj"</string> diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml index d3512ba38ef0..f89454a58a53 100644 --- a/packages/CredentialManager/res/values-be/strings.xml +++ b/packages/CredentialManager/res/values-be/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Іншыя спосабы ўваходу"</string> <string name="close_sheet" msgid="1393792015338908262">"Закрыць аркуш"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Вярнуцца да папярэдняй старонкі"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Закрыць"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Скарыстаць захаваны ключ доступу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Скарыстаць захаваныя спосабы ўваходу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблакіраваныя спосабы ўваходу"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Націсніце, каб разблакіраваць"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Няма даных для ўваходу"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Ва ўліковым запісе <xliff:g id="SOURCE">%1$s</xliff:g> адсутнічае інфармацыя для ўваходу"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіраваць спосабамі ўваходу"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншай прылады"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Скарыстаць іншую прыладу"</string> diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml index 35926ca216d6..530c8230d18b 100644 --- a/packages/CredentialManager/res/values-bg/strings.xml +++ b/packages/CredentialManager/res/values-bg/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Други мениджъри на пароли"</string> <string name="close_sheet" msgid="1393792015338908262">"Затваряне на таблицата"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Назад към предишната страница"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Затваряне"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Да се използва ли запазеният ви код за достъп за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Да се използват ли запазените ви данни за вход за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заключени мениджъри на пароли"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Докоснете, за да отключите"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Няма данни за вход"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> не съдържа данни за вход"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управление на данните за вход"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"От друго устройство"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Използване на друго устройство"</string> diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml index 3273aa48caba..c3f0e4b264b1 100644 --- a/packages/CredentialManager/res/values-bn/strings.xml +++ b/packages/CredentialManager/res/values-bn/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"অন্যান্য Password Manager"</string> <string name="close_sheet" msgid="1393792015338908262">"শিট বন্ধ করুন"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"আগের পৃষ্ঠায় ফিরে যান"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"বন্ধ করুন"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য আপনার সেভ করা পাসকী ব্যবহার করবেন?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য আপনার সেভ করা সাইন-ইন সম্পর্কিত ক্রেডেনশিয়াল ব্যবহার করবেন?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"লক করা Password Manager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"আনলক করতে ট্যাপ করুন"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"সাইন-ইন সম্পর্কিত তথ্য নেই"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g>-এ সাইন-ইন সম্পর্কিত কোনও তথ্য নেই"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"সাইন-ইন করার ক্রেডেনশিয়াল ম্যানেজ করুন"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য ডিভাইস থেকে"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"আলাদা ডিভাইস ব্যবহার করুন"</string> diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml index 27516513f363..d98061432492 100644 --- a/packages/CredentialManager/res/values-bs/strings.xml +++ b/packages/CredentialManager/res/values-bs/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Drugi upravitelji lozinki"</string> <string name="close_sheet" msgid="1393792015338908262">"Zatvaranje tabele"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Povratak na prethodnu stranicu"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Zatvaranje"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Koristiti sačuvani pristupni ključ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Koristiti sačuvanu prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zaključani upravitelji lozinki"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dodirnite da otključate"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nema podataka za prijavu"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nema informacija za prijavu na <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljajte prijavama"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"S drugog uređaja"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string> diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml index 0d115d5d08c5..afbfe505d9b0 100644 --- a/packages/CredentialManager/res/values-ca/strings.xml +++ b/packages/CredentialManager/res/values-ca/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Altres gestors de contrasenyes"</string> <string name="close_sheet" msgid="1393792015338908262">"Tanca el full"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Torna a la pàgina anterior"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Tanca"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vols utilitzar la clau d\'accés desada per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vols utilitzar l\'inici de sessió desat per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestors de contrasenyes bloquejats"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Toca per desbloquejar"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Sense informació d\'inici de sessió"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Sense informació d\'inici de sessió per a <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestiona els inicis de sessió"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Des d\'un altre dispositiu"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utilitza un dispositiu diferent"</string> diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml index f3e290bf65c4..72e5525e220b 100644 --- a/packages/CredentialManager/res/values-cs/strings.xml +++ b/packages/CredentialManager/res/values-cs/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Další správci hesel"</string> <string name="close_sheet" msgid="1393792015338908262">"Zavřít list"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Zpět na předchozí stránku"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Zavřít"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Použít uložený přístupový klíč pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Použít uložené přihlášení pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Uzamčení správci hesel"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Klepnutím odemknete"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Žádné informace o přihlášení"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> neobsahuje žádné přihlašovací údaje"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Spravovat přihlášení"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z jiného zařízení"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použít jiné zařízení"</string> diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml index 76c8a8138bd9..148bba83be33 100644 --- a/packages/CredentialManager/res/values-da/strings.xml +++ b/packages/CredentialManager/res/values-da/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Andre adgangskodeadministratorer"</string> <string name="close_sheet" msgid="1393792015338908262">"Luk arket"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gå tilbage til den forrige side"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Luk"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruge din gemte adgangsnøgle til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vil du bruge din gemte loginmetode til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låste adgangskodeadministratorer"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tryk for at låse op"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ingen loginoplysninger"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Der er ingen loginoplysninger i <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrer loginmetoder"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en anden enhed"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Brug en anden enhed"</string> diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml index adcaae4af520..103a3d2edc10 100644 --- a/packages/CredentialManager/res/values-de/strings.xml +++ b/packages/CredentialManager/res/values-de/strings.xml @@ -49,6 +49,8 @@ <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Zurück zur vorherigen Seite"</string> <!-- no translation found for accessibility_close_button (1163435587545377687) --> <skip /> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gespeicherten Passkey für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gespeicherte Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Gespeicherte Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> auswählen"</string> diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml index df1b1a718c45..8cb3f2816a26 100644 --- a/packages/CredentialManager/res/values-el/strings.xml +++ b/packages/CredentialManager/res/values-el/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Κλείσιμο φύλλου"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Επιστροφή στην προηγούμενη σελίδα"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Κλείσιμο"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Να χρησιμοποιηθεί το αποθηκευμένο κλειδί πρόσβασης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Να χρησιμοποιηθούν τα αποθηκευμένα στοιχεία σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Επιλογή αποθηκευμένων στοιχείων σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml index e350449cded6..ffba3ce6727b 100644 --- a/packages/CredentialManager/res/values-en-rAU/strings.xml +++ b/packages/CredentialManager/res/values-en-rAU/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Close"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml index f6ab350abbb5..32bbe449dde8 100644 --- a/packages/CredentialManager/res/values-en-rCA/strings.xml +++ b/packages/CredentialManager/res/values-en-rCA/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Close"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml index e350449cded6..ffba3ce6727b 100644 --- a/packages/CredentialManager/res/values-en-rGB/strings.xml +++ b/packages/CredentialManager/res/values-en-rGB/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Close"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml index e350449cded6..ffba3ce6727b 100644 --- a/packages/CredentialManager/res/values-en-rIN/strings.xml +++ b/packages/CredentialManager/res/values-en-rIN/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Close"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml index 7f5f0c11a479..49db2fc56ee7 100644 --- a/packages/CredentialManager/res/values-en-rXC/strings.xml +++ b/packages/CredentialManager/res/values-en-rXC/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Close"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml index d700ed65236e..91afadc9df11 100644 --- a/packages/CredentialManager/res/values-es-rUS/strings.xml +++ b/packages/CredentialManager/res/values-es-rUS/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Otros administradores de contraseñas"</string> <string name="close_sheet" msgid="1393792015338908262">"Cerrar hoja"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volver a la página anterior"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Cerrar"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Quieres usar tu llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"¿Quieres usar tu acceso guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Administradores de contraseñas bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Presiona para desbloquear"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"No hay información de acceso"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"No hay información de acceso en <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrar accesos"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Desde otro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otra voz"</string> diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml index ee056af4706c..b1ff41411138 100644 --- a/packages/CredentialManager/res/values-es/strings.xml +++ b/packages/CredentialManager/res/values-es/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Otros gestores de contraseñas"</string> <string name="close_sheet" msgid="1393792015338908262">"Cerrar hoja"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volver a la página anterior"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Cerrar"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Usar la llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"¿Usar el inicio de sesión guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestores de contraseñas bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tocar para desbloquear"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"No hay información de inicio de sesión"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"No hay información de inicio de sesión en <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionar inicios de sesión"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De otro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otro dispositivo"</string> diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml index accdea5fd7fc..5bacae35d09c 100644 --- a/packages/CredentialManager/res/values-et/strings.xml +++ b/packages/CredentialManager/res/values-et/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Muud paroolihaldurid"</string> <string name="close_sheet" msgid="1393792015338908262">"Sule leht"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Minge tagasi eelmisele lehele"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Sule"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud pääsuvõtit?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud sisselogimisandmeid?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Lukustatud paroolihaldurid"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Avamiseks puudutage"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Sisselogimisteave puudub"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Kontol <xliff:g id="SOURCE">%1$s</xliff:g> puudub sisselogimisteave"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Sisselogimisandmete haldamine"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Muus seadmes"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Kasuta teist seadet"</string> diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml index 18d653227578..9052bd2e0945 100644 --- a/packages/CredentialManager/res/values-eu/strings.xml +++ b/packages/CredentialManager/res/values-eu/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Beste pasahitz-kudeatzaile batzuk"</string> <string name="close_sheet" msgid="1393792015338908262">"Itxi orria"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Itzuli aurreko orrira"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Itxi"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde duzun sarbide-gakoa erabili nahi duzu?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde dituzun kredentzialak erabili nahi dituzu?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Blokeatutako pasahitz-kudeatzaileak"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Desblokeatzeko, sakatu hau"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ez dago saioa hasteko informaziorik"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Ez dago saioa hasteko informaziorik <xliff:g id="SOURCE">%1$s</xliff:g> kontuan"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kudeatu kredentzialak"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Beste gailu batean gordetakoak"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Erabili beste gailu bat"</string> diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml index 68ec685e419d..9e01bf0cef6b 100644 --- a/packages/CredentialManager/res/values-fa/strings.xml +++ b/packages/CredentialManager/res/values-fa/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"دیگر مدیران گذرواژه"</string> <string name="close_sheet" msgid="1393792015338908262">"بستن برگ"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"برگشتن به صفحه قبلی"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"بستن"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"گذرکلید ذخیرهشده برای <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ورود به سیستم ذخیرهشده برای <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"مدیران گذرواژه قفلشده"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"برای باز کردن قفل ضربه بزنید"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"اطلاعات ورود به سیستم موجود نیست"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"هیچ اطلاعات ورود به سیستمی در <xliff:g id="SOURCE">%1$s</xliff:g> وجود ندارد"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"مدیریت ورود به سیستمها"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"از دستگاهی دیگر"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استفاده از دستگاه دیگری"</string> diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml index 266a2a9297ee..268dbca45a58 100644 --- a/packages/CredentialManager/res/values-fi/strings.xml +++ b/packages/CredentialManager/res/values-fi/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Muut salasanojen ylläpitotyökalut"</string> <string name="close_sheet" msgid="1393792015338908262">"Sulje taulukko"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Takaisin edelliselle sivulle"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Sulje"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Käytetäänkö tallennettua avainkoodiasi täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Käytetäänkö tallennettuja kirjautumistietoja täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Lukitut salasanojen ylläpitotyökalut"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Avaa napauttamalla"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ei kirjautumistietoja"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Ei kirjautumistietoja (<xliff:g id="SOURCE">%1$s</xliff:g>)"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Muuta kirjautumistietoja"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Toiselta laitteelta"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Käytä toista laitetta"</string> diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml index 914ee55e4241..d5fd858a7867 100644 --- a/packages/CredentialManager/res/values-fr-rCA/strings.xml +++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml @@ -49,6 +49,8 @@ <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Retourner à la page précédente"</string> <!-- no translation found for accessibility_close_button (1163435587545377687) --> <skip /> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Utiliser votre connexion enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choisir une connexion enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml index faca62dfcd30..95917e10481a 100644 --- a/packages/CredentialManager/res/values-fr/strings.xml +++ b/packages/CredentialManager/res/values-fr/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Autres gestionnaires de mots de passe"</string> <string name="close_sheet" msgid="1393792015338908262">"Fermer la feuille"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Revenir à la page précédente"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Fermer"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Utiliser vos informations de connexion enregistrées pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestionnaires de mots de passe verrouillés"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Appuyer pour déverrouiller"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Aucune information de connexion"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Aucune info de connexion dans <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gérer les connexions"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Depuis un autre appareil"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string> diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml index 3b2d6f602510..88dc4a0afa20 100644 --- a/packages/CredentialManager/res/values-gl/strings.xml +++ b/packages/CredentialManager/res/values-gl/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Outros xestores de contrasinais"</string> <string name="close_sheet" msgid="1393792015338908262">"Pechar folla"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volver á páxina anterior"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Pechar"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Queres usar a clave de acceso gardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Queres usar o método de inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Xestores de contrasinais bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Toca para desbloquear"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Sen información de inicio de sesión"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Non hai información de inicio de sesión para <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Xestionar os métodos de inicio de sesión"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Doutro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar outro dispositivo"</string> diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml index d3339b746fa6..1237483f1b59 100644 --- a/packages/CredentialManager/res/values-gu/strings.xml +++ b/packages/CredentialManager/res/values-gu/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"અન્ય પાસવર્ડ મેનેજર"</string> <string name="close_sheet" msgid="1393792015338908262">"શીટ બંધ કરો"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"પાછલા પેજ પર પરત જાઓ"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"બંધ કરો"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે શું તમારી સાચવેલી પાસકીનો ઉપયોગ કરીએ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે શું તમારા સાચવેલા સાઇન-ઇનનો ઉપયોગ કરીએ?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"લૉક કરેલા પાસવર્ડ મેનેજર"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"અનલૉક કરવા માટે ટૅપ કરો"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"સાઇન-ઇનની કોઈ માહિતી નથી"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g>માં સાઇન-ઇનની કોઈ માહિતી નથી"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"સાઇન-ઇન મેનેજ કરો"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"કોઈ અન્ય ડિવાઇસમાંથી"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string> diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml index f2790f4e6e75..7f3bb4937988 100644 --- a/packages/CredentialManager/res/values-hi/strings.xml +++ b/packages/CredentialManager/res/values-hi/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"दूसरे पासवर्ड मैनेजर"</string> <string name="close_sheet" msgid="1393792015338908262">"शीट बंद करें"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"पिछले पेज पर वापस जाएं"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"बंद करें"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई पासकी का इस्तेमाल करना है?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई जानकारी का इस्तेमाल करना है?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक किए गए पासवर्ड मैनेजर"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलॉक करने के लिए टैप करें"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"साइन-इन करने से जुड़ी कोई जानकारी उपलब्ध नहीं है"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> में साइन-इन की जानकारी नहीं है"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इन करने की सुविधा को मैनेज करें"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"किसी दूसरे डिवाइस से"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"दूसरे डिवाइस का इस्तेमाल करें"</string> diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml index 3d813f9e1e39..7a8354ac770e 100644 --- a/packages/CredentialManager/res/values-hr/strings.xml +++ b/packages/CredentialManager/res/values-hr/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Drugi upravitelji zaporki"</string> <string name="close_sheet" msgid="1393792015338908262">"Zatvaranje lista"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Vratite se na prethodnu stranicu"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Zatvori"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite li upotrijebiti spremljeni pristupni ključ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite li upotrijebiti spremljene podatke za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Upravitelji zaključanih zaporki"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dodirnite za otključavanje"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nema podataka o prijavi"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nema podataka o prijavi u aplikaciji <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljanje prijavama"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na drugom uređaju"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string> diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml index e3b0fec5e672..ae136be950cb 100644 --- a/packages/CredentialManager/res/values-hu/strings.xml +++ b/packages/CredentialManager/res/values-hu/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Egyéb jelszókezelők"</string> <string name="close_sheet" msgid="1393792015338908262">"Munkalap bezárása"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Vissza az előző oldalra"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Bezárás"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett azonosítókulcsot használni?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett bejelentkezési adatait használni?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zárolt jelszókezelők"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Koppintson a feloldáshoz"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nincsenek bejelentkezési adatok"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nem találhatók bejelentkezési adatok itt: <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Bejelentkezési adatok kezelése"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Másik eszközről"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Másik eszköz használata"</string> diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml index 6cdc76fad3fc..6b7c97317504 100644 --- a/packages/CredentialManager/res/values-hy/strings.xml +++ b/packages/CredentialManager/res/values-hy/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Գաղտնաբառերի այլ կառավարիչներ"</string> <string name="close_sheet" msgid="1393792015338908262">"Փակել թերթը"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Անցնել նախորդ էջ"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Փակել"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Օգտագործե՞լ պահված անցաբառը <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Օգտագործե՞լ մուտքի պահված տվյալները <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Գաղտնաբառերի կողպված կառավարիչներ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Հպեք ապակողպելու համար"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Մուտքի տվյալներ չկան"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Մուտքի տվյալներ չկան այստեղ՝ <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Մուտքի կառավարում"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Մեկ այլ սարքից"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Օգտագործել այլ սարք"</string> diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml index f0f00896d155..9eb3c659e306 100644 --- a/packages/CredentialManager/res/values-in/strings.xml +++ b/packages/CredentialManager/res/values-in/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Pengelola sandi lainnya"</string> <string name="close_sheet" msgid="1393792015338908262">"Tutup sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Kembali ke halaman sebelumnya"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Tutup"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci sandi tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gunakan info login tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Pengelola sandi terkunci"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Ketuk untuk membuka kunci"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Tidak ada info login"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Tidak ada info login di <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kelola login"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Dari perangkat lain"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan perangkat lain"</string> diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml index 7ee8b5d3e813..b6270580cd11 100644 --- a/packages/CredentialManager/res/values-is/strings.xml +++ b/packages/CredentialManager/res/values-is/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Önnur aðgangsorðastjórnun"</string> <string name="close_sheet" msgid="1393792015338908262">"Loka blaði"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Fara aftur á fyrri síðu"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Loka"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Notað vistaðan aðgangslykil fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Nota vistaða innskráningu fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Læst aðgangsorðastjórnun"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Ýttu til að opna"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Engar innskráningarupplýsingar"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Engar innskráningarupplýsingar á <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Stjórna innskráningu"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Úr öðru tæki"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Nota annað tæki"</string> diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml index 7f39c1db42a4..9497ceae9f53 100644 --- a/packages/CredentialManager/res/values-it/strings.xml +++ b/packages/CredentialManager/res/values-it/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Altri gestori delle password"</string> <string name="close_sheet" msgid="1393792015338908262">"Chiudi il foglio"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Torna alla pagina precedente"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Chiudi"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vuoi usare la passkey salvata per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vuoi usare l\'accesso salvato per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestori delle password bloccati"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tocca per sbloccare"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nessuna informazione di accesso"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Non sono presenti dati di accesso in <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestisci gli accessi"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Da un altro dispositivo"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usa un dispositivo diverso"</string> diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml index 9100b517ad55..9197ac65c416 100644 --- a/packages/CredentialManager/res/values-iw/strings.xml +++ b/packages/CredentialManager/res/values-iw/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"מנהלי סיסמאות אחרים"</string> <string name="close_sheet" msgid="1393792015338908262">"סגירת הגיליון"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"חזרה לדף הקודם"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"סגירה"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"להשתמש במפתח גישה שנשמר עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"להשתמש בפרטי הכניסה שנשמרו עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"מנהלי סיסמאות נעולים"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"יש להקיש כדי לבטל את הנעילה"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"אין פרטי כניסה"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"אין פרטי כניסה ב-<xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ניהול כניסות"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ממכשיר אחר"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"צריך להשתמש במכשיר אחר"</string> diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml index c49dd398d328..3c97777637bf 100644 --- a/packages/CredentialManager/res/values-ja/strings.xml +++ b/packages/CredentialManager/res/values-ja/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"シートを閉じます"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"前のページに戻ります"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"閉じる"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したパスキーを使用しますか?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したログイン情報を使用しますか?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したログイン情報の選択"</string> diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml index f5eb7c94efa0..4d0d9f7e6d95 100644 --- a/packages/CredentialManager/res/values-ka/strings.xml +++ b/packages/CredentialManager/res/values-ka/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"ფურცლის დახურვა"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"წინა გვერდზე დაბრუნება"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"დახურვა"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"გსურთ თქვენი დამახსოვრებული წვდომის გასაღების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"გსურთ თქვენი დამახსოვრებული სისტემაში შესვლის მონაცემების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"აირჩიეთ სისტემაში შესვლის ინფორმაცია აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml index 8864cb43a258..4be32d86d48e 100644 --- a/packages/CredentialManager/res/values-kk/strings.xml +++ b/packages/CredentialManager/res/values-kk/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Басқа құпия сөз менеджерлері"</string> <string name="close_sheet" msgid="1393792015338908262">"Парақты жабу"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Алдыңғы бетке оралу"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Жабу"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған кіру кілті пайдаланылсын ба?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған тіркелу деректері пайдаланылсын ба?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Құлыпталған құпия сөз менеджерлері"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Құлыпты ашу үшін түртіңіз."</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Кіру ақпараты жоқ."</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> аккаунтында кіру туралы ешқандай ақпарат жоқ."</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіру әрекеттерін басқару"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан жасау"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Басқа құрылғыны пайдалану"</string> diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml index f257789f9237..313c0c552512 100644 --- a/packages/CredentialManager/res/values-km/strings.xml +++ b/packages/CredentialManager/res/values-km/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"បិទសន្លឹក"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ត្រឡប់ទៅទំព័រមុនវិញ"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"បិទ"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ប្រើកូដសម្ងាត់ដែលបានរក្សាទុករបស់អ្នកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ប្រើការចូលគណនីដែលបានរក្សាទុករបស់អ្នកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ជ្រើសរើសការចូលគណនីដែលបានរក្សាទុកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml index c41bd6312243..750c51bf0c81 100644 --- a/packages/CredentialManager/res/values-kn/strings.xml +++ b/packages/CredentialManager/res/values-kn/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"ಶೀಟ್ ಮುಚ್ಚಿರಿ"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ಹಿಂದಿನ ಪುಟಕ್ಕೆ ಹಿಂದಿರುಗಿ"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"ಮುಚ್ಚಿರಿ"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ನಿಮ್ಮ ಪಾಸ್ಕೀ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ಸೈನ್-ಇನ್ ಮಾಹಿತಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml index 20b734a9ed5f..89b5a3f977f6 100644 --- a/packages/CredentialManager/res/values-ko/strings.xml +++ b/packages/CredentialManager/res/values-ko/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"기타 비밀번호 관리자"</string> <string name="close_sheet" msgid="1393792015338908262">"시트 닫기"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"이전 페이지로 돌아가기"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"닫기"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 패스키를 사용하시겠습니까?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 로그인 정보를 사용하시겠습니까?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"잠긴 비밀번호 관리자"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"탭하여 잠금 해제"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"로그인 정보 없음"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g>의 로그인 정보 없음"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"로그인 관리"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"다른 기기에서"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"다른 기기 사용"</string> diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml index 895d0e7f63db..3e172b4ace67 100644 --- a/packages/CredentialManager/res/values-ky/strings.xml +++ b/packages/CredentialManager/res/values-ky/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Башка сырсөздөрдү башкаргычтар"</string> <string name="close_sheet" msgid="1393792015338908262">"Баракты жабуу"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Мурунку бетке кайтуу"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Жабуу"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган мүмкүндүк алуу ачкычын колдоносузбу?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган кирүү параметрин колдоносузбу?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Кулпуланган сырсөздөрдү башкаргычтар"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Кулпусун ачуу үчүн таптаңыз"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Аккаунтка кирүү тууралуу маалымат жок"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> аккаунтунда кирүү маалыматы жок"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кирүү параметрлерин тескөө"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Башка түзмөктөн"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Башка түзмөктү колдонуу"</string> diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml index 757bf135b494..f08d522c71a0 100644 --- a/packages/CredentialManager/res/values-lo/strings.xml +++ b/packages/CredentialManager/res/values-lo/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"ຕົວຈັດການລະຫັດຜ່ານອື່ນໆ"</string> <string name="close_sheet" msgid="1393792015338908262">"ປິດຊີດ"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ກັບຄືນໄປຫາໜ້າກ່ອນໜ້ານີ້"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"ປິດ"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ໃຊ້ກະແຈຜ່ານທີ່ບັນທຶກໄວ້ຂອງທ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ໃຊ້ການເຂົ້າສູ່ລະບົບທີ່ບັນທຶກໄວ້ຂອງທ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ຕົວຈັດການລະຫັດຜ່ານທີ່ລັອກໄວ້"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ແຕະເພື່ອປົດລັອກ"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"ບໍ່ມີຂໍ້ມູນການເຂົ້າສູ່ລະບົບ"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"ບໍ່ມີຂໍ້ມູນການເຂົ້າສູ່ລະບົບໃນ <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ຈັດການການເຂົ້າສູ່ລະບົບ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ຈາກອຸປະກອນອື່ນ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ໃຊ້ອຸປະກອນອື່ນ"</string> diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml index d75993f66286..71b50a834c07 100644 --- a/packages/CredentialManager/res/values-lt/strings.xml +++ b/packages/CredentialManager/res/values-lt/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Kitos slaptažodžių tvarkyklės"</string> <string name="close_sheet" msgid="1393792015338908262">"Uždaryti lapą"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Grįžti į ankstesnį puslapį"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Uždaryti"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Naudoti išsaugotą „passkey“ programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Naudoti išsaugotą prisijungimo informaciją programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Užrakintos slaptažodžių tvarkyklės"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Palieskite, kad atrakintumėte"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Prisijungimo informacijos nėra"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nėra prisijungimo informacijos <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Tvarkyti prisijungimo informaciją"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Naudojant kitą įrenginį"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Naudoti kitą įrenginį"</string> diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml index 01c6d55dd471..86a7b8ac65f4 100644 --- a/packages/CredentialManager/res/values-lv/strings.xml +++ b/packages/CredentialManager/res/values-lv/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Citi paroļu pārvaldnieki"</string> <string name="close_sheet" msgid="1393792015338908262">"Aizvērt lapu"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Atgriezties iepriekšējā lapā"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Aizvērt"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vai izmantot saglabāto piekļuves atslēgu lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vai izmantot saglabāto pierakstīšanās informāciju lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Paroļu pārvaldnieki, kuros nepieciešams autentificēties"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Pieskarieties, lai atbloķētu"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nav pierakstīšanās informācijas"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Kontā <xliff:g id="SOURCE">%1$s</xliff:g> nav pierakstīšanās informācijas."</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Pierakstīšanās informācijas pārvaldība"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"No citas ierīces"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Izmantot citu ierīci"</string> diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml index a844bc978cb5..393bca1dd836 100644 --- a/packages/CredentialManager/res/values-mk/strings.xml +++ b/packages/CredentialManager/res/values-mk/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Други управници со лозинки"</string> <string name="close_sheet" msgid="1393792015338908262">"Затворете го листот"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Врати се на претходната страница"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Затвори"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Да се користи вашиот зачуван криптографски клуч за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Да се користи вашето зачувано најавување за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заклучени управници со лозинки"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Допрете за да отклучите"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Нема податоци за најавување"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Нема податоци за најавување во <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управувајте со најавувањата"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Од друг уред"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Употребете друг уред"</string> diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml index de88b28d56c7..efe614c2c04f 100644 --- a/packages/CredentialManager/res/values-ml/strings.xml +++ b/packages/CredentialManager/res/values-ml/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"ഷീറ്റ് അടയ്ക്കുക"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"മുമ്പത്തെ പേജിലേക്ക് മടങ്ങുക"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"അടയ്ക്കുക"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി നിങ്ങൾ സംരക്ഷിച്ച പാസ്കീ ഉപയോഗിക്കണോ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി നിങ്ങൾ സംരക്ഷിച്ച സൈൻ ഇൻ ഉപയോഗിക്കണോ?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി ഒരു സംരക്ഷിച്ച സൈൻ ഇൻ തിരഞ്ഞെടുക്കുക"</string> diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml index ee5d66f11b5c..6c7ba7a49f32 100644 --- a/packages/CredentialManager/res/values-mn/strings.xml +++ b/packages/CredentialManager/res/values-mn/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Нууц үгний бусад менежер"</string> <string name="close_sheet" msgid="1393792015338908262">"Хүснэгтийг хаах"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Өмнөх хуудас руу буцах"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Хаах"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д өөрийн хадгалсан passkey-г ашиглах уу?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д хадгалсан нэвтрэх мэдээллээ ашиглах уу?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Түгжээтэй нууц үгний менежерүүд"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Түгжээг тайлахын тулд товшино уу"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ямар ч нэвтрэх мэдээлэл байхгүй"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g>-д ямар ч нэвтрэх мэдээлэл алга"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Нэвтрэлтийг удирдах"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Өөр төхөөрөмжөөс"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Өөр төхөөрөмж ашиглах"</string> diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml index bc032124dc7f..ca0480c59b24 100644 --- a/packages/CredentialManager/res/values-mr/strings.xml +++ b/packages/CredentialManager/res/values-mr/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"इतर पासवर्ड व्यवस्थापक"</string> <string name="close_sheet" msgid="1393792015338908262">"शीट बंद करा"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"मागील पेजवर परत जा"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"बंद करा"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी तुमची सेव्ह केलेली पासकी वापरायची का?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी तुमचे सेव्ह केलेले साइन-इन वापरायचे का?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक केलेले पासवर्ड व्यवस्थापक"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलॉक करण्यासाठी टॅप करा"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"साइन-इन माहिती नाही"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> मध्ये कोणतीही साइन-इन माहिती नाही"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन-इन व्यवस्थापित करा"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"दुसऱ्या डिव्हाइस वरून"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"वेगळे डिव्हाइस वापरा"</string> diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml index ab2d9536266a..7719f91575d4 100644 --- a/packages/CredentialManager/res/values-ms/strings.xml +++ b/packages/CredentialManager/res/values-ms/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Tutup helaian"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Kembali ke halaman sebelumnya"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Tutup"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci laluan anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gunakan maklumat log masuk anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pilih log masuk yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml index 92a9e49cab4d..9b60d5c0a6c3 100644 --- a/packages/CredentialManager/res/values-my/strings.xml +++ b/packages/CredentialManager/res/values-my/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"အခြားစကားဝှက်မန်နေဂျာများ"</string> <string name="close_sheet" msgid="1393792015338908262">"စာမျက်နှာ ပိတ်ရန်"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ယခင်စာမျက်နှာကို ပြန်သွားပါ"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"ပိတ်ရန်"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသောလျှို့ဝှက်ကီး သုံးမလား။"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသောလက်မှတ်ထိုးဝင်မှု သုံးမလား။"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"လော့ခ်ချထားသည့် စကားဝှက်မန်နေဂျာများ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ဖွင့်ရန် တို့ပါ"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"လက်မှတ်ထိုးဝင်သည့် အချက်အလက် မရှိပါ"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> တွင် လက်မှတ်ထိုးဝင်ရန်အချက်အလက် မရှိပါ"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"လက်မှတ်ထိုးဝင်မှုများ စီမံခြင်း"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"စက်နောက်တစ်ခုမှ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"အခြားစက်သုံးရန်"</string> diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml index ac8f7c122225..88692cb8513f 100644 --- a/packages/CredentialManager/res/values-nb/strings.xml +++ b/packages/CredentialManager/res/values-nb/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Andre løsninger for passordlagring"</string> <string name="close_sheet" msgid="1393792015338908262">"Lukk arket"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gå tilbake til den forrige siden"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Lukk"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruke den lagrede tilgangsnøkkelen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vil du bruke den lagrede påloggingen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låste løsninger for passordlagring"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Trykk for å låse opp"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ingen påloggingsinformasjon"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Ingen påloggingsinformasjon i <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrer pålogginger"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en annen enhet"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Bruk en annen enhet"</string> diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml index 70ae649c7477..45c9f8ce0fcb 100644 --- a/packages/CredentialManager/res/values-ne/strings.xml +++ b/packages/CredentialManager/res/values-ne/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"अन्य पासवर्ड म्यानेजरहरू"</string> <string name="close_sheet" msgid="1393792015338908262">"पाना बन्द गर्नुहोस्"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"अघिल्लो पेजमा फर्कनुहोस्"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"बन्द गर्नुहोस्"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"आफूले सेभ गरेको पासकी प्रयोग गरी <xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्ने हो?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"आफूले सेभ गरेको साइन इनसम्बन्धी जानकारी प्रयोग गरी <xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्ने हो?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लक गरिएका पासवर्ड म्यानेजरहरू"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलक गर्न ट्याप गर्नुहोस्"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"साइन गर्न प्रयोग गरिनु पर्ने जानकारी उपलब्ध छैन"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> मा साइन इन गर्नेसम्बन्धी कुनै पनि जानकारी छैन"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इनसम्बन्धी विकल्पहरू व्यवस्थापन गर्नुहोस्"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"अर्को डिभाइसका लागि"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गरी हेर्नुहोस्"</string> diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml index f3d72886dcad..32307ea2910f 100644 --- a/packages/CredentialManager/res/values-nl/strings.xml +++ b/packages/CredentialManager/res/values-nl/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Andere wachtwoordmanagers"</string> <string name="close_sheet" msgid="1393792015338908262">"Blad sluiten"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Ga terug naar de vorige pagina"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Sluiten"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Je opgeslagen toegangssleutel voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Je opgeslagen inloggegevens voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vergrendelde wachtwoordmanagers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tik om te ontgrendelen"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Geen inloggegevens"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Geen inloggevens in <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Inloggegevens beheren"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via een ander apparaat"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Een ander apparaat gebruiken"</string> diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml index 539b3ddbd3c2..953e9b2b3a29 100644 --- a/packages/CredentialManager/res/values-or/strings.xml +++ b/packages/CredentialManager/res/values-or/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"ଅନ୍ୟ Password Manager"</string> <string name="close_sheet" msgid="1393792015338908262">"ସିଟ ବନ୍ଦ କରନ୍ତୁ"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ପୂର୍ବବର୍ତ୍ତୀ ପୃଷ୍ଠାକୁ ଫେରନ୍ତୁ"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"ବନ୍ଦ କରନ୍ତୁ"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଆପଣଙ୍କ ପାସକୀ ବ୍ୟବହାର କରିବେ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଆପଣଙ୍କ ସାଇନ-ଇନ ବ୍ୟବହାର କରିବେ?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ଲକ ଥିବା Password Manager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ଅନଲକ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"କୌଣସି ସାଇନ-ଇନ ସୂଚନା ନାହିଁ"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g>ରେ କୌଣସି ସାଇନ-ଇନ ସୂଚନା ନାହିଁ"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ସାଇନ-ଇନ ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ଅନ୍ୟ ଏକ ଡିଭାଇସରୁ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ଏକ ଭିନ୍ନ ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string> diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml index 7e4676a5e56f..2dd6a2ca2e3e 100644 --- a/packages/CredentialManager/res/values-pa/strings.xml +++ b/packages/CredentialManager/res/values-pa/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"ਹੋਰ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ"</string> <string name="close_sheet" msgid="1393792015338908262">"ਸ਼ੀਟ ਬੰਦ ਕਰੋ"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ਪਿਛਲੇ ਪੰਨੇ \'ਤੇ ਵਾਪਸ ਜਾਓ"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"ਬੰਦ ਕਰੋ"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਆਪਣੀ ਰੱਖਿਅਤ ਕੀਤੀ ਪਾਸਕੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਆਪਣੀ ਰੱਖਿਅਤ ਕੀਤੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ਲਾਕ ਕੀਤੇ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> ਵਿੱਚ ਕੋਈ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਨਹੀਂ"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ਸਾਈਨ-ਇਨਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ਹੋਰ ਡੀਵਾਈਸ ਤੋਂ"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ਵੱਖਰੇ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml index c77d846674d8..74a0d8fddfdc 100644 --- a/packages/CredentialManager/res/values-pl/strings.xml +++ b/packages/CredentialManager/res/values-pl/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Inne menedżery haseł"</string> <string name="close_sheet" msgid="1393792015338908262">"Zamknij arkusz"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Wróć do poprzedniej strony"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Zamknij"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Użyć zapisanego klucza dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Użyć zapisanych danych logowania dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zablokowane menedżery haseł"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Kliknij, aby odblokować"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Brak danych logowania"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g>: brak danych logowania"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Zarządzanie danymi logowania"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na innym urządzeniu"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Użyj innego urządzenia"</string> diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml index 90433e171664..9eaf99bc4056 100644 --- a/packages/CredentialManager/res/values-pt-rBR/strings.xml +++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Fechar página"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Voltar à página anterior"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Fechar"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar suas informações de login salvas para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolher um login salvo para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml index 1abc85d24ae2..ad927e0110ca 100644 --- a/packages/CredentialManager/res/values-pt-rPT/strings.xml +++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Fechar folha"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volte à página anterior"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Fechar"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar a sua token de acesso guardada na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar o seu início de sessão guardado na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolha um início de sessão guardado para a app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml index 90433e171664..9eaf99bc4056 100644 --- a/packages/CredentialManager/res/values-pt/strings.xml +++ b/packages/CredentialManager/res/values-pt/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Fechar página"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Voltar à página anterior"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Fechar"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar suas informações de login salvas para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolher um login salvo para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml index 11b3b4987f5b..198ff1d65a9a 100644 --- a/packages/CredentialManager/res/values-ro/strings.xml +++ b/packages/CredentialManager/res/values-ro/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Alți manageri de parole"</string> <string name="close_sheet" msgid="1393792015338908262">"Închide foaia"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Revino la pagina precedentă"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Închide"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Folosești cheia de acces salvată pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Folosești datele de conectare salvate pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Manageri de parole blocate"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Atinge pentru a debloca"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Fără informații de conectare"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nu există informații de conectare în contul <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionează acreditările"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De pe alt dispozitiv"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Folosește alt dispozitiv"</string> diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml index c7d253eb4b7d..846df541961e 100644 --- a/packages/CredentialManager/res/values-ru/strings.xml +++ b/packages/CredentialManager/res/values-ru/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Другие менеджеры паролей"</string> <string name="close_sheet" msgid="1393792015338908262">"Закрыть лист"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Вернуться на предыдущую страницу"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Закрыть"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Использовать сохраненный ключ доступа для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Использовать сохраненные учетные данные для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблокированные менеджеры паролей"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Нажмите для разблокировки"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Необходимо ввести учетные данные"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"В аккаунте <xliff:g id="SOURCE">%1$s</xliff:g> нет учетных данных"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управление входом"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"С другого устройства"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Использовать другое устройство"</string> diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml index 36ce3f8588c7..1df8ea236be8 100644 --- a/packages/CredentialManager/res/values-si/strings.xml +++ b/packages/CredentialManager/res/values-si/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"වෙනත් මුරපද කළමනාකරුවන්"</string> <string name="close_sheet" msgid="1393792015338908262">"පත්රය වසන්න"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"පෙර පිටුවට ආපසු යන්න"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"වසන්න"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා ඔබේ සුරැකි මුරයතුර භාවිතා කරන්න ද?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා ඔබේ සුරැකි පුරනය භාවිතා කරන්න ද?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"අගුළු දැමූ මුරපද කළමනාකරුවන්"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"අගුළු හැරීමට තට්ටු කරන්න"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"පුරනය වීමේ තතු නැත"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> තුළ පුරනය වීමේ තතු නැත"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"පුරනය වීම් කළමනාකරණය කරන්න"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"වෙනත් උපාංගයකින්"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"වෙනස් උපාංගයක් භාවිතා කරන්න"</string> diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml index 09bf265e1e19..eb187965dd8c 100644 --- a/packages/CredentialManager/res/values-sk/strings.xml +++ b/packages/CredentialManager/res/values-sk/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Iní správcovia hesiel"</string> <string name="close_sheet" msgid="1393792015338908262">"Zavrieť hárok"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Prejsť späť na predchádzajúcu stránku"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Zavrieť"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> použiť uložený prístupový kľúč?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> použiť uložené prihlasovacie údaje?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Správcovia uzamknutých hesiel"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Odomknúť klepnutím"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Žiadne prihlasovacie údaje"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Žiadne prihlasovacie údaje v zdroji <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Spravovať prihlasovacie údaje"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z iného zariadenia"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použiť iné zariadenie"</string> diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml index 29b6410e77c0..15bcbae8c133 100644 --- a/packages/CredentialManager/res/values-sl/strings.xml +++ b/packages/CredentialManager/res/values-sl/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Zapri list"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Nazaj na prejšnjo stran"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Zapri"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite uporabiti shranjeni ključ za dostop do aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite uporabiti shranjene podatke za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Izberite shranjene podatke za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml index 6650668abce6..1e4653836789 100644 --- a/packages/CredentialManager/res/values-sq/strings.xml +++ b/packages/CredentialManager/res/values-sq/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Menaxherët e tjerë të fjalëkalimeve"</string> <string name="close_sheet" msgid="1393792015338908262">"Mbyll fletën"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Kthehu te faqja e mëparshme"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Mbyll"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Të përdoret fjalëkalimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Të përdoret identifikimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Menaxherët e fjalëkalimeve të kyçura"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Trokit për të shkyçur"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nuk ka informacione për identifikimin"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nuk ka informacione regjistrimi në <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Identifikimet e menaxhimit"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Nga një pajisje tjetër"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Përdor një pajisje tjetër"</string> diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml index 877d45c94c4a..bbb54633084d 100644 --- a/packages/CredentialManager/res/values-sr/strings.xml +++ b/packages/CredentialManager/res/values-sr/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Други менаџери лозинки"</string> <string name="close_sheet" msgid="1393792015338908262">"Затворите табелу"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Вратите се на претходну страницу"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Затворите"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Желите да користите сачувани приступни кôд за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Желите да користите сачуване податке за пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Менаџери закључаних лозинки"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Додирните да бисте откључали"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Нема података за пријављивање"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Нема података за пријављивање у: <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управљајте пријављивањима"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Са другог уређаја"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Користи други уређај"</string> diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml index 9ec317ef8a70..3d85e14ebb27 100644 --- a/packages/CredentialManager/res/values-sv/strings.xml +++ b/packages/CredentialManager/res/values-sv/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Andra lösenordshanterare"</string> <string name="close_sheet" msgid="1393792015338908262">"Stäng kalkylarket"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gå tillbaka till föregående sida"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Stäng"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vill du använda din sparade nyckel för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vill du använda dina sparade inloggningsuppgifter för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låsta lösenordshanterare"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tryck för att låsa upp"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ingen inloggningsinformation"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Det finns inga inloggningsuppgifter i <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Hantera inloggningar"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via en annan enhet"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Använd en annan enhet"</string> diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml index 1a5499c3a654..f0f1db5ef08c 100644 --- a/packages/CredentialManager/res/values-sw/strings.xml +++ b/packages/CredentialManager/res/values-sw/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Vidhibiti vinginevyo vya manenosiri"</string> <string name="close_sheet" msgid="1393792015338908262">"Funga laha"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Rudi kwenye ukurasa uliotangulia"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Funga"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Ungependa kutumia ufunguo wa siri uliohifadhiwa wa<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Ungependa kutumia kitambulisho kilichohifadhiwa cha kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vidhibiti vya manenosiri vilivyofungwa"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Gusa ili ufungue"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Hakuna maelezo ya kuingia katika akaunti"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Hakuna maelezo ya kuingia katika akaunti kwenye <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Dhibiti michakato ya kuingia katika akaunti"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kutoka kwenye kifaa kingine"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Tumia kifaa tofauti"</string> diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml index 19a871f1c644..09a4fcbbd3f5 100644 --- a/packages/CredentialManager/res/values-ta/strings.xml +++ b/packages/CredentialManager/res/values-ta/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"பிற கடவுச்சொல் நிர்வாகிகள்"</string> <string name="close_sheet" msgid="1393792015338908262">"ஷீட்டை மூடும்"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"முந்தைய பக்கத்திற்குச் செல்லும்"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"மூடும்"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட கடவுக்குறியீட்டைப் பயன்படுத்தவா?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட உள்நுழைவுத் தகவலைப் பயன்படுத்தவா?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"பூட்டப்பட்ட கடவுச்சொல் நிர்வாகிகள்"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"அன்லாக் செய்ய தட்டவும்"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"உள்நுழைவு விவரங்கள் இல்லை"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> கணக்கில் உள்நுழைவு விவரங்கள் இல்லை"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"உள்நுழைவுகளை நிர்வகித்தல்"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"மற்றொரு சாதனத்திலிருந்து பயன்படுத்து"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"வேறு சாதனத்தைப் பயன்படுத்து"</string> diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml index 04ee0feb7c25..e93ff204f981 100644 --- a/packages/CredentialManager/res/values-te/strings.xml +++ b/packages/CredentialManager/res/values-te/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"షీట్ను మూసివేయండి"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"మునుపటి పేజీకి తిరిగి వెళ్లండి"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"మూసివేస్తుంది"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం మీ సేవ్ చేసిన పాస్-కీ వివరాలను ఉపయోగించాలా?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం మీరు సేవ్ చేసిన సైన్ ఇన్ వివరాలను ఉపయోగించాలా?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం సేవ్ చేసిన సైన్ ఇన్ వివరాలను ఎంచుకోండి"</string> diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml index 29e87a0bf331..e44a66d043b8 100644 --- a/packages/CredentialManager/res/values-th/strings.xml +++ b/packages/CredentialManager/res/values-th/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"เครื่องมือจัดการรหัสผ่านอื่นๆ"</string> <string name="close_sheet" msgid="1393792015338908262">"ปิดชีต"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"กลับไปยังหน้าก่อนหน้า"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"ปิด"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ใช้พาสคีย์ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ใช่ไหม"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ใช้การลงชื่อเข้าใช้ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ใช่ไหม"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"เครื่องมือจัดการรหัสผ่านที่ล็อกไว้"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"แตะเพื่อปลดล็อก"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"ไม่มีข้อมูลการลงชื่อเข้าใช้"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"ไม่มีข้อมูลการลงชื่อเข้าใช้ใน <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"จัดการการลงชื่อเข้าใช้"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"จากอุปกรณ์อื่น"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ใช้อุปกรณ์อื่น"</string> diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml index 773039fc75ff..6b48af148bca 100644 --- a/packages/CredentialManager/res/values-tl/strings.xml +++ b/packages/CredentialManager/res/values-tl/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Iba pang password manager"</string> <string name="close_sheet" msgid="1393792015338908262">"Isara ang sheet"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Bumalik sa nakaraang page"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Isara"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gamitin ang iyong naka-save na passkey para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gamitin ang iyong naka-save na sign-in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Mga naka-lock na password manager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"I-tap para i-unlock"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Walang impormasyon sa pag-sign in"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Walang impormasyon sa pag-sign in sa <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Pamahalaan ang mga sign-in"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Mula sa ibang device"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gumamit ng ibang device"</string> diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml index 083add361914..b0a354c7ce51 100644 --- a/packages/CredentialManager/res/values-tr/strings.xml +++ b/packages/CredentialManager/res/values-tr/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Diğer şifre yöneticileri"</string> <string name="close_sheet" msgid="1393792015338908262">"Sayfayı kapat"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Önceki sayfaya geri dön"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Kapat"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı şifre anahtarınız kullanılsın mı?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı oturum açma bilgileriniz kullanılsın mı?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Kilitli şifre yöneticileri"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Kilidi açmak için dokunun"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Oturum açma bilgisi yok"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> hesabında oturum açma bilgisi yok"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Oturum açma bilgilerini yönetin"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başka bir cihazdan"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Farklı bir cihaz kullan"</string> diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml index dd112e0330c7..ec12bc6df62a 100644 --- a/packages/CredentialManager/res/values-uk/strings.xml +++ b/packages/CredentialManager/res/values-uk/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Інші менеджери паролів"</string> <string name="close_sheet" msgid="1393792015338908262">"Закрити аркуш"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Повернутися на попередню сторінку"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Закрити"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Використати збережений ключ доступу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Використати збережені дані для входу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблоковані менеджери паролів"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Торкніться, щоб розблокувати"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Немає даних для входу"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Немає даних для входу в обліковий запис <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Керування даними для входу"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншого пристрою"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Використовувати інший пристрій"</string> diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml index 3a704fe72aa9..b4bf77f060b2 100644 --- a/packages/CredentialManager/res/values-ur/strings.xml +++ b/packages/CredentialManager/res/values-ur/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"دیگر پاس ورڈ مینیجرز"</string> <string name="close_sheet" msgid="1393792015338908262">"شیٹ بند کریں"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"گزشتہ صفحے پر واپس جائیں"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"بند کریں"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اپنی محفوظ کردہ پاس کی استعمال کریں؟"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اپنے محفوظ کردہ سائن ان کو استعمال کریں؟"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"مقفل کردہ پاس ورڈ مینیجرز"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"غیر مقفل کرنے کیلئے تھپتھپائیں"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"سائن ان کی کوئی معلومات نہیں"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> میں سائن ان کی کوئی معلومات نہیں ہے"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"سائن انز کا نظم کریں"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"دوسرے آلے سے"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ایک مختلف آلہ استعمال کریں"</string> diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml index 8248d52f54b2..92c40eea8ab3 100644 --- a/packages/CredentialManager/res/values-uz/strings.xml +++ b/packages/CredentialManager/res/values-uz/strings.xml @@ -48,6 +48,8 @@ <string name="close_sheet" msgid="1393792015338908262">"Varaqni yopish"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Avvalgi sahifaga qaytish"</string> <string name="accessibility_close_button" msgid="1163435587545377687">"Yopish"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> + <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan kalit ishlatilsinmi?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan maʼlumotlar ishlatilsinmi?"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> hisob maʼlumotlarini tanlang"</string> diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml index 058e20721706..dd0aeed5cd9b 100644 --- a/packages/CredentialManager/res/values-vi/strings.xml +++ b/packages/CredentialManager/res/values-vi/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Trình quản lý mật khẩu khác"</string> <string name="close_sheet" msgid="1393792015338908262">"Đóng trang tính"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Quay lại trang trước"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Đóng"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Dùng mã xác thực bạn đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Dùng thông tin đăng nhập bạn đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Trình quản lý mật khẩu đã khoá"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Nhấn để mở khoá"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Không có thông tin đăng nhập"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Không có thông tin đăng nhập trong <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Quản lý thông tin đăng nhập"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Từ một thiết bị khác"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Dùng thiết bị khác"</string> diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml index 976ef57f8739..87bdce3ead2d 100644 --- a/packages/CredentialManager/res/values-zh-rCN/strings.xml +++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"其他密码管理工具"</string> <string name="close_sheet" msgid="1393792015338908262">"关闭工作表"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"返回上一页"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"关闭"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"将您已保存的通行密钥用于<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"将您已保存的登录信息用于<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已锁定的密码管理工具"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"点按即可解锁"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"无登录信息"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> 中没有任何登录信息"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登录信息"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"通过另一台设备"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他设备"</string> diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml index 0014d7dcec28..b8d5fc56d5f9 100644 --- a/packages/CredentialManager/res/values-zh-rHK/strings.xml +++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"其他密碼管理工具"</string> <string name="close_sheet" msgid="1393792015338908262">"閂工作表"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"返回上一頁"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"關閉"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密鑰嗎?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資料嗎?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已鎖定的密碼管理工具"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"輕按即可解鎖"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"沒有登入資料"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> 中沒有登入資料"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登入資料"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string> diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml index 61735849007b..885753ac4280 100644 --- a/packages/CredentialManager/res/values-zh-rTW/strings.xml +++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"其他密碼管理工具"</string> <string name="close_sheet" msgid="1393792015338908262">"關閉功能表"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"返回上一頁"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"關閉"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密碼金鑰嗎?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資訊嗎?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已鎖定的密碼管理工具"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"輕觸即可解鎖"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"沒有登入資訊"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> 中沒有登入資訊"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登入資訊"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string> diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml index a1c3230d9836..f077d571e8a7 100644 --- a/packages/CredentialManager/res/values-zu/strings.xml +++ b/packages/CredentialManager/res/values-zu/strings.xml @@ -47,7 +47,8 @@ <string name="other_password_manager" msgid="565790221427004141">"Abanye abaphathi bephasiwedi"</string> <string name="close_sheet" msgid="1393792015338908262">"Vala ishidi"</string> <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Buyela emuva ekhasini langaphambilini"</string> - <!-- no translation found for accessibility_close_button (1163435587545377687) --> + <string name="accessibility_close_button" msgid="1163435587545377687">"Vala"</string> + <!-- no translation found for accessibility_snackbar_dismiss (3456598374801836120) --> <skip /> <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Sebenzisa ukhiye wakho wokungena olondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Sebenzisa ukungena kwakho ngemvume okulondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> @@ -60,8 +61,7 @@ <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Abaphathi bephasiwedi abakhiyiwe"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Thepha ukuze uvule"</string> <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Alukho ulwazi lokungena ngemvume"</string> - <!-- no translation found for no_sign_in_info_in (2641118151920288356) --> - <skip /> + <string name="no_sign_in_info_in" msgid="2641118151920288356">"Alukho ulwazi lokungena ngemvume lwe-<xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Phatha ukungena ngemvume"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kusukela kwenye idivayisi"</string> <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Sebenzisa idivayisi ehlukile"</string> diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml index ee512427fa9c..f655d6b174d5 100644 --- a/packages/CredentialManager/res/values/strings.xml +++ b/packages/CredentialManager/res/values/strings.xml @@ -42,7 +42,7 @@ <!-- Title for subsection of "Learn more about passkeys" screen about seamless transition. [CHAR LIMIT=80] --> <string name="seamless_transition_title">Seamless transition</string> <!-- Detail for subsection of "Learn more about passkeys" screen about seamless transition. [CHAR LIMIT=500] --> - <string name="seamless_transition_detail">As we move towards a passwordless future, passwords will still be available alongside passkeys.</string> + <string name="seamless_transition_detail">As we move towards a passwordless future, passwords will still be available alongside passkeys</string> <!-- This appears as the title of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] --> <string name="choose_provider_title">Choose where to save your <xliff:g id="createTypes" example="passkeys">%1$s</xliff:g></string> <!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] --> @@ -67,9 +67,8 @@ <string name="create_passkey_in_other_device_title">Create passkey in another device?</string> <!-- This appears as the title of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] --> <string name="use_provider_for_all_title">Use <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g> for all your sign-ins?</string> - <!-- TODO: Check the wording here. --> - <!-- This appears as the description body of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] --> - <string name="use_provider_for_all_description">This password manager will store your passwords and passkeys to help you easily sign in</string> + <!-- This appears as the description body of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=300] --> + <string name="use_provider_for_all_description">This password manager for <xliff:g id="username" example="becket@gmail.com">%1$s</xliff:g> will store your passwords and passkeys to help you easily sign in</string> <!-- This is a label for a button that sets this password manager as the default. [CHAR LIMIT=20] --> <string name="set_as_default">Set as default</string> <!-- This is a label for a button that makes this password manager be used just in this specific case. [CHAR LIMIT=20] --> @@ -111,7 +110,7 @@ <!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] --> <string name="get_dialog_button_label_continue">Continue</string> <!-- Separator for sign-in type and username in a sign-in entry. --> - <string name="get_dialog_sign_in_type_username_separator" translatable="false">" - "</string> + <string name="get_dialog_sign_in_type_username_separator" translatable="false">" • "</string> <!-- This text is followed by a list of one or more options. [CHAR LIMIT=80] --> <string name="get_dialog_title_sign_in_options">Sign-in options</string> <!-- Column heading for displaying sign-ins for a specific username. [CHAR LIMIT=80] --> diff --git a/packages/CredentialManager/res/values/themes.xml b/packages/CredentialManager/res/values/themes.xml index c7e47962472f..428c85ac721f 100644 --- a/packages/CredentialManager/res/values/themes.xml +++ b/packages/CredentialManager/res/values/themes.xml @@ -1,11 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <style name="Theme.CredentialSelector" parent="@android:style/ThemeOverlay.Material"> + <style name="Theme.CredentialSelector" parent="@*android:style/ThemeOverlay.DeviceDefault.Accent.DayNight"> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> - <item name="android:statusBarColor">@android:color/transparent</item> - <item name="android:navigationBarColor">@android:color/transparent</item> </style> </resources>
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index 0e604ce2cf3a..b32fe3fef00d 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -42,11 +42,13 @@ import com.android.credentialmanager.createflow.DisabledProviderInfo import com.android.credentialmanager.createflow.EnabledProviderInfo import com.android.credentialmanager.createflow.RequestDisplayInfo import com.android.credentialmanager.getflow.GetCredentialUiState +import com.android.credentialmanager.getflow.findAutoSelectEntry import androidx.credentials.CreateCredentialRequest.DisplayInfo import androidx.credentials.CreatePublicKeyCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.GetPasswordOption import androidx.credentials.GetPublicKeyCredentialOption +import com.android.credentialmanager.common.ProviderActivityState import java.time.Instant @@ -73,7 +75,7 @@ class CredentialManagerRepo( requestInfo = intent.extras?.getParcelable( RequestInfo.EXTRA_REQUEST_INFO, RequestInfo::class.java - ) ?: testCreatePasskeyRequestInfo() + ) ?: testGetRequestInfo() val originName: String? = when (requestInfo.type) { RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin @@ -128,10 +130,20 @@ class CredentialManagerRepo( getCredentialUiState = null, ) } - RequestInfo.TYPE_GET -> UiState( - createCredentialUiState = null, - getCredentialUiState = getCredentialInitialUiState(originName)!!, - ) + RequestInfo.TYPE_GET -> { + val getCredentialInitialUiState = getCredentialInitialUiState(originName)!! + val autoSelectEntry = + findAutoSelectEntry(getCredentialInitialUiState.providerDisplayInfo) + UiState( + createCredentialUiState = null, + getCredentialUiState = getCredentialInitialUiState, + selectedEntry = autoSelectEntry, + providerActivityState = + if (autoSelectEntry == null) ProviderActivityState.NOT_APPLICABLE + else ProviderActivityState.READY_TO_LAUNCH, + isAutoSelectFlow = autoSelectEntry != null, + ) + } else -> throw IllegalStateException("Unrecognized request type: ${requestInfo.type}") } } @@ -407,8 +419,8 @@ class CredentialManagerRepo( val credentialData = request.credentialData return RequestInfo.newCreateRequestInfo( Binder(), - CreateCredentialRequest.Builder(credentialData, Bundle()) - .setType("androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL") + CreateCredentialRequest.Builder("androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL", + credentialData, Bundle()) .setIsSystemProviderRequired(false) .setAlwaysSendAppInfoToProvider(true) .build(), @@ -420,8 +432,8 @@ class CredentialManagerRepo( val request = CreatePasswordRequest("beckett-bakert@gmail.com", "password123") return RequestInfo.newCreateRequestInfo( Binder(), - CreateCredentialRequest.Builder(request.credentialData, request.candidateQueryData) - .setType(TYPE_PASSWORD_CREDENTIAL) + CreateCredentialRequest.Builder(TYPE_PASSWORD_CREDENTIAL, + request.credentialData, request.candidateQueryData) .setIsSystemProviderRequired(false) .setAlwaysSendAppInfoToProvider(true) .build(), @@ -438,8 +450,7 @@ class CredentialManagerRepo( ) return RequestInfo.newCreateRequestInfo( Binder(), - CreateCredentialRequest.Builder(data, Bundle()) - .setType("other-sign-ins") + CreateCredentialRequest.Builder("other-sign-ins", data, Bundle()) .setIsSystemProviderRequired(false) .setAlwaysSendAppInfoToProvider(true) .build(), diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index 9b7139ccc26e..ce18335769a8 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -44,6 +44,9 @@ data class UiState( val selectedEntry: BaseEntry? = null, val providerActivityState: ProviderActivityState = ProviderActivityState.NOT_APPLICABLE, val dialogState: DialogState = DialogState.ACTIVE, + // True if the UI has one and only one auto selectable entry. Its provider activity will be + // launched immediately, and canceling it will cancel the whole UI flow. + val isAutoSelectFlow: Boolean = false, ) class CredentialSelectorViewModel( @@ -96,13 +99,20 @@ class CredentialSelectorViewModel( val resultCode = providerActivityResult.resultCode val resultData = providerActivityResult.data if (resultCode == Activity.RESULT_CANCELED) { - // Re-display the CredMan UI if the user canceled from the provider UI. - Log.d(Constants.LOG_TAG, "The provider activity was cancelled," + - " re-displaying our UI.") - uiState = uiState.copy( - selectedEntry = null, - providerActivityState = ProviderActivityState.NOT_APPLICABLE, - ) + // Re-display the CredMan UI if the user canceled from the provider UI, or cancel + // the UI if this is the auto select flow. + if (uiState.isAutoSelectFlow) { + Log.d(Constants.LOG_TAG, "The auto selected provider activity was cancelled," + + " ending the credential manager activity.") + onUserCancel() + } else { + Log.d(Constants.LOG_TAG, "The provider activity was cancelled," + + " re-displaying our UI.") + uiState = uiState.copy( + selectedEntry = null, + providerActivityState = ProviderActivityState.NOT_APPLICABLE, + ) + } } else { if (entry != null) { Log.d( @@ -130,6 +140,11 @@ class CredentialSelectorViewModel( onInternalError() } + fun onIllegalUiState(errorMessage: String) { + Log.w(Constants.LOG_TAG, errorMessage) + onInternalError() + } + private fun onInternalError() { Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state") credManRepo.onParsingFailureCancel() diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index a834994a5b0f..b5c8989de618 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -52,9 +52,7 @@ import androidx.credentials.CreateCustomCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.CredentialOption import androidx.credentials.CreatePublicKeyCredentialRequest -import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged import androidx.credentials.GetPublicKeyCredentialOption -import androidx.credentials.GetPublicKeyCredentialOptionPrivileged import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL import androidx.credentials.provider.Action import androidx.credentials.provider.AuthenticationAction @@ -62,8 +60,7 @@ import androidx.credentials.provider.CreateEntry import androidx.credentials.provider.CustomCredentialEntry import androidx.credentials.provider.PasswordCredentialEntry import androidx.credentials.provider.PublicKeyCredentialEntry -import androidx.credentials.provider.RemoteCreateEntry -import androidx.credentials.provider.RemoteCredentialEntry +import androidx.credentials.provider.RemoteEntry import org.json.JSONObject // TODO: remove all !! checks @@ -151,7 +148,10 @@ class GetFlowUtils { icon = providerIcon, displayName = providerLabel, credentialEntryList = getCredentialOptionInfoList( - it.providerFlattenedComponentName, it.credentialEntries, context + providerId = it.providerFlattenedComponentName, + providerLabel = providerLabel, + credentialEntries = it.credentialEntries, + context = context ), authenticationEntryList = getAuthenticationEntryList( it.providerFlattenedComponentName, @@ -186,8 +186,6 @@ class GetFlowUtils { ) if (credentialOptionJetpack is GetPublicKeyCredentialOption) { credentialOptionJetpack.preferImmediatelyAvailableCredentials - } else if (credentialOptionJetpack is GetPublicKeyCredentialOptionPrivileged) { - credentialOptionJetpack.preferImmediatelyAvailableCredentials } else { false } @@ -206,6 +204,7 @@ class GetFlowUtils { */ private fun getCredentialOptionInfoList( providerId: String, + providerLabel: String, credentialEntries: List<Entry>, context: Context, ): List<CredentialEntryInfo> { @@ -216,6 +215,7 @@ class GetFlowUtils { is PasswordCredentialEntry -> { result.add(CredentialEntryInfo( providerId = providerId, + providerDisplayName = providerLabel, entryKey = it.key, entrySubkey = it.subkey, pendingIntent = credentialEntry.pendingIntent, @@ -224,13 +224,17 @@ class GetFlowUtils { credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(), userName = credentialEntry.username.toString(), displayName = credentialEntry.displayName?.toString(), - icon = credentialEntry.icon?.loadDrawable(context), + icon = credentialEntry.icon.loadDrawable(context), + shouldTintIcon = credentialEntry.isDefaultIcon ?: false, lastUsedTimeMillis = credentialEntry.lastUsedTime, + isAutoSelectable = credentialEntry.isAutoSelectAllowed && + credentialEntry.autoSelectAllowedFromOption, )) } is PublicKeyCredentialEntry -> { result.add(CredentialEntryInfo( providerId = providerId, + providerDisplayName = providerLabel, entryKey = it.key, entrySubkey = it.subkey, pendingIntent = credentialEntry.pendingIntent, @@ -239,13 +243,17 @@ class GetFlowUtils { credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(), userName = credentialEntry.username.toString(), displayName = credentialEntry.displayName?.toString(), - icon = credentialEntry.icon?.loadDrawable(context), + icon = credentialEntry.icon.loadDrawable(context), + shouldTintIcon = credentialEntry.isDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, + isAutoSelectable = credentialEntry.isAutoSelectAllowed && + credentialEntry.autoSelectAllowedFromOption, )) } is CustomCredentialEntry -> { result.add(CredentialEntryInfo( providerId = providerId, + providerDisplayName = providerLabel, entryKey = it.key, entrySubkey = it.subkey, pendingIntent = credentialEntry.pendingIntent, @@ -254,8 +262,11 @@ class GetFlowUtils { credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(), userName = credentialEntry.title.toString(), displayName = credentialEntry.subtitle?.toString(), - icon = credentialEntry.icon?.loadDrawable(context), + icon = credentialEntry.icon.loadDrawable(context), + shouldTintIcon = credentialEntry.isDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, + isAutoSelectable = credentialEntry.isAutoSelectAllowed && + credentialEntry.autoSelectAllowedFromOption, )) } else -> Log.d( @@ -324,7 +335,7 @@ class GetFlowUtils { if (remoteEntry == null) { return null } - val structuredRemoteEntry = RemoteCredentialEntry.fromSlice(remoteEntry.slice) + val structuredRemoteEntry = RemoteEntry.fromSlice(remoteEntry.slice) ?: return null return RemoteEntryInfo( providerId = providerId, @@ -436,7 +447,7 @@ class CreateFlowUtils { createCredentialRequestJetpack.password, CredentialType.PASSWORD, appLabel, - context.getDrawable(R.drawable.ic_password) ?: return null, + context.getDrawable(R.drawable.ic_password_24) ?: return null, preferImmediatelyAvailableCredentials = false, ) is CreatePublicKeyCredentialRequest -> { @@ -448,27 +459,18 @@ class CreateFlowUtils { createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, ) } - is CreatePublicKeyCredentialRequestPrivileged -> { - newRequestDisplayInfoFromPasskeyJson( - requestJson = createCredentialRequestJetpack.requestJson, - appLabel = appLabel, - context = context, - preferImmediatelyAvailableCredentials = - createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, - ) - } is CreateCustomCredentialRequest -> { // TODO: directly use the display info once made public val displayInfo = CreateCredentialRequest.DisplayInfo .parseFromCredentialDataBundle(createCredentialRequest.credentialData) ?: return null RequestDisplayInfo( - title = displayInfo.userId, - subtitle = displayInfo.userDisplayName, + title = displayInfo.userId.toString(), + subtitle = displayInfo.userDisplayName?.toString(), type = CredentialType.UNKNOWN, appName = appLabel, typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context) - ?: context.getDrawable(R.drawable.ic_other_sign_in) ?: return null, + ?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null, preferImmediatelyAvailableCredentials = false, ) } @@ -625,7 +627,7 @@ class CreateFlowUtils { remoteEntry: Entry?, ): RemoteInfo? { return if (remoteEntry != null) { - val structuredRemoteEntry = RemoteCreateEntry.fromSlice(remoteEntry.slice) + val structuredRemoteEntry = RemoteEntry.fromSlice(remoteEntry.slice) ?: return null RemoteInfo( providerId = providerId, @@ -656,7 +658,7 @@ class CreateFlowUtils { displayName, CredentialType.PASSKEY, appLabel, - context.getDrawable(R.drawable.ic_passkey) ?: return null, + context.getDrawable(R.drawable.ic_passkey_24) ?: return null, preferImmediatelyAvailableCredentials, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt b/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt index 9216429eac52..26aadd9d5dee 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt @@ -25,12 +25,14 @@ import android.credentials.Credential.TYPE_PASSWORD_CREDENTIAL import android.credentials.ui.AuthenticationEntry import android.credentials.ui.Entry import android.net.Uri +import android.os.Bundle import android.provider.Settings +import androidx.credentials.provider.BeginGetPasswordOption +import androidx.credentials.provider.BeginGetPublicKeyCredentialOption import androidx.credentials.provider.CreateEntry import androidx.credentials.provider.PasswordCredentialEntry import androidx.credentials.provider.PublicKeyCredentialEntry -import androidx.credentials.provider.RemoteCreateEntry -import androidx.credentials.provider.RemoteCredentialEntry +import androidx.credentials.provider.RemoteEntry import java.time.Instant @@ -82,7 +84,7 @@ class GetTestUtils { return Entry( key, subkey, - RemoteCredentialEntry(pendingIntent).slice + RemoteEntry(pendingIntent).slice ) } @@ -137,7 +139,8 @@ class GetTestUtils { intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT) ) - val passwordEntry = PasswordCredentialEntry.Builder(context, userName, pendingIntent) + val passwordEntry = PasswordCredentialEntry.Builder( + context, userName, pendingIntent, BeginGetPasswordOption(Bundle(), "id")) .setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime).build() return Entry(key, subkey, passwordEntry.slice, Intent()) } @@ -149,17 +152,23 @@ class GetTestUtils { userName: String, userDisplayName: String?, lastUsedTime: Instant?, + isAutoSelectAllowed: Boolean = false, ): Entry { - val intent = Intent("com.androidauth.androidvault.CONFIRM_PASSWORD") - .setPackage("com.androidauth.androidvault") - intent.putExtra("provider_extra_sample", "testprovider") - val pendingIntent = PendingIntent.getActivity( - context, 1, - intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT - or PendingIntent.FLAG_ONE_SHOT) + val intent = Intent(Settings.ACTION_SYNC_SETTINGS) + val pendingIntent = + PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) + val candidateQueryData = Bundle() + candidateQueryData.putBoolean( + "androidx.credentials.BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED", + isAutoSelectAllowed ) - val passkeyEntry = PublicKeyCredentialEntry.Builder(context, userName, pendingIntent) - .setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime).build() + val passkeyEntry = PublicKeyCredentialEntry.Builder( + context, + userName, + pendingIntent, + BeginGetPublicKeyCredentialOption(candidateQueryData, "id", "requestjson") + ).setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime) + .setAutoSelectAllowed(isAutoSelectAllowed).build() return Entry(key, subkey, passkeyEntry.slice, Intent()) } } @@ -232,7 +241,7 @@ class CreateTestUtils { return Entry( key, subkey, - RemoteCreateEntry(pendingIntent).slice + RemoteEntry(pendingIntent).slice ) } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt index 335d58ac85f6..307d95313ec8 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt @@ -306,10 +306,6 @@ fun rememberModalBottomSheetState( * @param sheetContentColor The preferred content color provided by the bottom sheet to its * children. Defaults to the matching content color for [sheetBackgroundColor], or if that is not * a color from the theme, this will keep the same content color set above the bottom sheet. - * @param scrimColor The color of the scrim that is applied to the rest of the screen when the - * bottom sheet is visible. If the color passed is [Color.Unspecified], then a scrim will no - * longer be applied and the bottom sheet will not block interaction with the rest of the screen - * when visible. * @param content The content of rest of the screen. */ @Composable @@ -322,7 +318,6 @@ fun ModalBottomSheetLayout( sheetElevation: Dp = ModalBottomSheetDefaults.Elevation, sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface, sheetContentColor: Color = contentColorFor(sheetBackgroundColor), - scrimColor: Color = ModalBottomSheetDefaults.scrimColor, content: @Composable () -> Unit ) { val scope = rememberCoroutineScope() @@ -332,7 +327,7 @@ fun ModalBottomSheetLayout( Box(Modifier.fillMaxSize()) { content() Scrim( - color = scrimColor, + color = ModalBottomSheetDefaults.scrimColor, onDismiss = { if (sheetState.confirmStateChange(Hidden)) { scope.launch { sheetState.hide() } @@ -505,5 +500,5 @@ object ModalBottomSheetDefaults { */ val scrimColor: Color @Composable - get() = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.32f) + get() = MaterialTheme.colorScheme.scrim.copy(alpha = .32f) }
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt index c4d96ccf51f8..edc902e41e9a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt @@ -18,7 +18,6 @@ package com.android.credentialmanager.common.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier @@ -27,6 +26,7 @@ import com.android.credentialmanager.common.material.ModalBottomSheetLayout import com.android.credentialmanager.common.material.ModalBottomSheetValue import com.android.credentialmanager.common.material.rememberModalBottomSheetState import com.android.credentialmanager.ui.theme.EntryShape +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme /** Draws a modal bottom sheet with the same styles and effects shared by various flows. */ @Composable @@ -39,11 +39,10 @@ fun ModalBottomSheet( skipHalfExpanded = true ) ModalBottomSheetLayout( - sheetBackgroundColor = MaterialTheme.colorScheme.surface, + sheetBackgroundColor = LocalAndroidColorScheme.current.colorSurfaceBright, modifier = Modifier.background(Color.Transparent), sheetState = state, sheetContent = sheetContent, - scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f), sheetShape = EntryShape.TopRoundedCorner, ) {} LaunchedEffect(state.currentValue) { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt index cc73089a96e7..3976f9a305ab 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt @@ -25,12 +25,13 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import com.android.credentialmanager.ui.theme.Shapes +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme /** * Container card for the whole sheet. @@ -49,9 +50,7 @@ fun SheetContainerCard( modifier = modifier.fillMaxWidth().wrapContentHeight(), border = null, colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - ElevationTokens.Level1 - ), + containerColor = LocalAndroidColorScheme.current.colorSurfaceBright, ), ) { if (topAppBar != null) { @@ -83,7 +82,7 @@ fun CredentialContainerCard( ) { Card( modifier = modifier.fillMaxWidth().wrapContentHeight(), - shape = MaterialTheme.shapes.medium, + shape = Shapes.medium, border = null, colors = CardDefaults.cardColors( containerColor = Color.Transparent, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt index bffa40e83f30..192354258fb2 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import com.android.credentialmanager.R import com.android.credentialmanager.ui.theme.EntryShape +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme import com.android.credentialmanager.ui.theme.Shapes @Composable @@ -73,7 +74,14 @@ fun Entry( passwordValue: String? = null, /** If true, draws a trailing lock icon. */ isLockedAuthEntry: Boolean = false, + enforceOneLine: Boolean = false, ) { + val iconPadding = Modifier.wrapContentSize().padding( + // Horizontal padding should be 16dp, but the suggestion chip itself + // has 8dp horizontal elements padding + start = 8.dp, top = 16.dp, bottom = 16.dp + ) + val iconSize = Modifier.size(24.dp) SuggestionChip( modifier = modifier.fillMaxWidth().wrapContentHeight(), onClick = onClick, @@ -81,13 +89,23 @@ fun Entry( label = { Row( horizontalArrangement = Arrangement.SpaceBetween, - modifier = Modifier.fillMaxWidth().padding(all = 16.dp), + modifier = Modifier.fillMaxWidth().padding( + // Total end padding should be 16dp, but the suggestion chip itself + // has 8dp horizontal elements padding + horizontal = 8.dp, vertical = 16.dp, + ), + // Make sure the trailing icon and text column are centered vertically. verticalAlignment = Alignment.CenterVertically, ) { - Column(modifier = Modifier.wrapContentSize()) { - SmallTitleText(entryHeadlineText) + // Apply weight so that the trailing icon can always show. + Column(modifier = Modifier.wrapContentHeight().fillMaxWidth().weight(1f)) { + SmallTitleText(text = entryHeadlineText, enforceOneLine = enforceOneLine) if (passwordValue != null) { - Row(modifier = Modifier.fillMaxWidth()) { + Row( + modifier = Modifier.fillMaxWidth().padding(top = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Start, + ) { val visualTransformation = remember { PasswordVisualTransformation() } val originalPassword by remember { mutableStateOf(passwordValue) @@ -99,9 +117,14 @@ fun Entry( ).text.text ) } - BodySmallText(displayedPassword.value) + BodySmallText( + text = displayedPassword.value, + // Apply weight to allow visibility button to render first so that + // it doesn't get squeezed out by a super long password. + modifier = Modifier.wrapContentSize().weight(1f, fill = false), + ) ToggleVisibilityButton( - modifier = Modifier.padding(start = 5.dp).size(24.dp), + modifier = Modifier.padding(start = 12.dp).size(24.dp), onToggle = { if (it) { displayedPassword.value = originalPassword @@ -114,14 +137,14 @@ fun Entry( ) } } else if (entrySecondLineText != null) { - BodySmallText(entrySecondLineText) + BodySmallText(text = entrySecondLineText, enforceOneLine = enforceOneLine) } if (entryThirdLineText != null) { - BodySmallText(entryThirdLineText) + BodySmallText(text = entryThirdLineText, enforceOneLine = enforceOneLine) } } if (isLockedAuthEntry) { - Box(modifier = Modifier.wrapContentSize().padding(end = 16.dp)) { + Box(modifier = Modifier.wrapContentSize().padding(start = 16.dp)) { Icon( imageVector = Icons.Outlined.Lock, // Decorative purpose only. @@ -137,10 +160,9 @@ fun Entry( if (iconImageBitmap != null) { if (shouldApplyIconImageBitmapTint) { { - Box(modifier = Modifier.wrapContentSize() - .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) { + Box(modifier = iconPadding) { Icon( - modifier = Modifier.size(24.dp), + modifier = iconSize, bitmap = iconImageBitmap, tint = MaterialTheme.colorScheme.onSurfaceVariant, // Decorative purpose only. @@ -150,10 +172,9 @@ fun Entry( } } else { { - Box(modifier = Modifier.wrapContentSize() - .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) { + Box(modifier = iconPadding) { Image( - modifier = Modifier.size(24.dp), + modifier = iconSize, bitmap = iconImageBitmap, // Decorative purpose only. contentDescription = null, @@ -163,10 +184,9 @@ fun Entry( } } else if (iconImageVector != null) { { - Box(modifier = Modifier.wrapContentSize() - .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) { + Box(modifier = iconPadding) { Icon( - modifier = Modifier.size(24.dp), + modifier = iconSize, imageVector = iconImageVector, tint = MaterialTheme.colorScheme.onSurfaceVariant, // Decorative purpose only. @@ -176,10 +196,9 @@ fun Entry( } } else if (iconPainter != null) { { - Box(modifier = Modifier.wrapContentSize() - .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) { + Box(modifier = iconPadding) { Icon( - modifier = Modifier.size(24.dp), + modifier = iconSize, painter = iconPainter, tint = MaterialTheme.colorScheme.onSurfaceVariant, // Decorative purpose only. @@ -192,9 +211,7 @@ fun Entry( }, border = null, colors = SuggestionChipDefaults.suggestionChipColors( - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - ElevationTokens.Level3 - ), + containerColor = LocalAndroidColorScheme.current.colorSurfaceContainerHigh, // TODO: remove? labelColor = MaterialTheme.colorScheme.onSurfaceVariant, iconContentColor = MaterialTheme.colorScheme.onSurfaceVariant, @@ -317,7 +334,7 @@ fun MoreOptionTopAppBar( contentDescription = stringResource( R.string.accessibility_back_arrow_button ), - modifier = Modifier.size(16.dp), + modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt new file mode 100644 index 000000000000..a6195237d139 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt @@ -0,0 +1,40 @@ +/* + * 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.credentialmanager.common.ui + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import com.android.compose.SystemUiController +import com.android.credentialmanager.common.material.ModalBottomSheetDefaults +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme + +@Composable +fun setTransparentSystemBarsColor(sysUiController: SystemUiController) { + sysUiController.setSystemBarsColor(color = Color.Transparent, darkIcons = false) +} + +@Composable +fun setBottomSheetSystemBarsColor(sysUiController: SystemUiController) { + sysUiController.setStatusBarColor( + color = ModalBottomSheetDefaults.scrimColor, + darkIcons = false + ) + sysUiController.setNavigationBarColor( + color = LocalAndroidColorScheme.current.colorSurfaceBright, + darkIcons = false + ) +}
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt index 8af729ecdc25..22871bcbe767 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow /** * The headline for a screen. E.g. "Create a passkey for X", "Choose a saved sign-in for X". @@ -57,12 +58,14 @@ fun BodyMediumText(text: String, modifier: Modifier = Modifier) { * Body-small typography; on-surface-variant color. */ @Composable -fun BodySmallText(text: String, modifier: Modifier = Modifier) { +fun BodySmallText(text: String, modifier: Modifier = Modifier, enforceOneLine: Boolean = false) { Text( modifier = modifier.wrapContentSize(), text = text, color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodySmall, + overflow = TextOverflow.Ellipsis, + maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE ) } @@ -83,12 +86,14 @@ fun LargeTitleText(text: String, modifier: Modifier = Modifier) { * Title-small typography; on-surface color. */ @Composable -fun SmallTitleText(text: String, modifier: Modifier = Modifier) { +fun SmallTitleText(text: String, modifier: Modifier = Modifier, enforceOneLine: Boolean = false) { Text( modifier = modifier.wrapContentSize(), text = text, color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.titleSmall, + overflow = TextOverflow.Ellipsis, + maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index 00b7d0057746..9fe789934f1b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -1,4 +1,18 @@ -@file:OptIn(ExperimentalMaterial3Api::class) +/* + * 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.credentialmanager.createflow @@ -15,11 +29,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.Divider -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.NewReleases import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.outlined.QrCodeScanner import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf @@ -31,6 +45,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.graphics.drawable.toBitmap +import com.android.compose.rememberSystemUiController import com.android.credentialmanager.CredentialSelectorViewModel import com.android.credentialmanager.R import com.android.credentialmanager.common.BaseEntry @@ -51,6 +66,7 @@ import com.android.credentialmanager.common.ui.MoreOptionTopAppBar import com.android.credentialmanager.common.ui.SheetContainerCard import com.android.credentialmanager.common.ui.PasskeyBenefitRow import com.android.credentialmanager.common.ui.HeadlineText +import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor @Composable fun CreateCredentialScreen( @@ -58,6 +74,8 @@ fun CreateCredentialScreen( createCredentialUiState: CreateCredentialUiState, providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult> ) { + val sysUiController = rememberSystemUiController() + setBottomSheetSystemBarsColor(sysUiController) ModalBottomSheet( sheetContent = { // Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim @@ -115,11 +133,20 @@ fun CreateCredentialScreen( viewModel::createFlowOnDisabledProvidersSelected, onRemoteEntrySelected = viewModel::createFlowOnEntrySelected, ) - CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard( - providerInfo = createCredentialUiState.activeEntry?.activeProvider!!, - onChangeDefaultSelected = viewModel::createFlowOnChangeDefaultSelected, - onUseOnceSelected = viewModel::createFlowOnUseOnceSelected, - ) + CreateScreenState.MORE_OPTIONS_ROW_INTRO -> { + if (createCredentialUiState.activeEntry == null) { + viewModel.onIllegalUiState("Expect active entry to be non-null" + + " upon default provider dialog.") + } else { + MoreOptionsRowIntroCard( + selectedEntry = createCredentialUiState.activeEntry, + onIllegalScreenState = viewModel::onIllegalUiState, + onChangeDefaultSelected = + viewModel::createFlowOnChangeDefaultSelected, + onUseOnceSelected = viewModel::createFlowOnUseOnceSelected, + ) + } + } CreateScreenState.EXTERNAL_ONLY_SELECTION -> ExternalOnlySelectionCard( requestDisplayInfo = createCredentialUiState.requestDisplayInfo, activeRemoteEntry = @@ -325,7 +352,8 @@ fun MoreOptionsSelectionCard( else onBackCreationSelectionButtonSelected, ) }) { - item { Divider(thickness = 16.dp, color = Color.Transparent) } + item { Divider(thickness = 8.dp, color = Color.Transparent) } // Top app bar has a 8dp + // bottom padding already item { CredentialContainerCard { Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { @@ -370,23 +398,31 @@ fun MoreOptionsSelectionCard( @Composable fun MoreOptionsRowIntroCard( - providerInfo: EnabledProviderInfo, + selectedEntry: ActiveEntry, + onIllegalScreenState: (String) -> Unit, onChangeDefaultSelected: () -> Unit, onUseOnceSelected: () -> Unit, ) { + val entryInfo = selectedEntry.activeEntryInfo + if (entryInfo !is CreateOptionInfo) { + onIllegalScreenState("Encountered unexpected type of entry during the default provider" + + " dialog: ${entryInfo::class}") + return + } SheetContainerCard { item { HeadlineIcon(imageVector = Icons.Outlined.NewReleases) } item { Divider(thickness = 24.dp, color = Color.Transparent) } item { HeadlineText( text = stringResource( - R.string.use_provider_for_all_title, - providerInfo.displayName - ) + R.string.use_provider_for_all_title, selectedEntry.activeProvider.displayName) ) } item { Divider(thickness = 24.dp, color = Color.Transparent) } - item { BodyMediumText(text = stringResource(R.string.use_provider_for_all_description)) } + item { + BodyMediumText(text = stringResource( + R.string.use_provider_for_all_description, entryInfo.userProviderDisplayName)) + } item { CtaButtonRow( leftButton = { @@ -511,7 +547,7 @@ fun ExternalOnlySelectionCard( onConfirm: () -> Unit, ) { SheetContainerCard { - item { HeadlineIcon(painter = painterResource(R.drawable.ic_other_devices)) } + item { HeadlineIcon(imageVector = Icons.Outlined.QrCodeScanner) } item { Divider(thickness = 16.dp, color = Color.Transparent) } item { HeadlineText(text = stringResource(R.string.create_passkey_in_other_device_title)) } item { Divider(thickness = 24.dp, color = Color.Transparent) } @@ -614,6 +650,7 @@ fun PrimaryCreateOptionRow( // This subtitle would never be null for create password requestDisplayInfo.subtitle ?: "" else null, + enforceOneLine = true, ) } @@ -690,7 +727,7 @@ fun RemoteEntryRow( ) { Entry( onClick = { onRemoteEntrySelected(remoteInfo) }, - iconPainter = painterResource(R.drawable.ic_other_devices), + iconImageVector = Icons.Outlined.QrCodeScanner, entryHeadlineText = stringResource(R.string.another_device), ) }
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index 192fa15714c6..4332fb34ce79 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -69,7 +69,7 @@ class CreateOptionInfo( entrySubkey: String, pendingIntent: PendingIntent?, fillInIntent: Intent?, - val userProviderDisplayName: String?, + val userProviderDisplayName: String, val profileIcon: Drawable?, val passwordCount: Int?, val passkeyCount: Int?, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index c5028c25c5da..a9f994db430a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -28,6 +28,8 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.QrCodeScanner import androidx.compose.material3.Divider import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -39,6 +41,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.graphics.drawable.toBitmap +import com.android.compose.rememberSystemUiController import com.android.credentialmanager.CredentialSelectorViewModel import com.android.credentialmanager.R import com.android.credentialmanager.common.BaseEntry @@ -57,6 +60,8 @@ import com.android.credentialmanager.common.ui.SnackbarActionText import com.android.credentialmanager.common.ui.HeadlineText import com.android.credentialmanager.common.ui.CredentialListSectionHeader import com.android.credentialmanager.common.ui.Snackbar +import com.android.credentialmanager.common.ui.setTransparentSystemBarsColor +import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor @Composable fun GetCredentialScreen( @@ -64,13 +69,16 @@ fun GetCredentialScreen( getCredentialUiState: GetCredentialUiState, providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult> ) { + val sysUiController = rememberSystemUiController() if (getCredentialUiState.currentScreenState == GetScreenState.REMOTE_ONLY) { + setTransparentSystemBarsColor(sysUiController) RemoteCredentialSnackBarScreen( onClick = viewModel::getFlowOnMoreOptionOnSnackBarSelected, onCancel = viewModel::onUserCancel, ) } else if (getCredentialUiState.currentScreenState == GetScreenState.UNLOCKED_AUTH_ENTRIES_ONLY) { + setTransparentSystemBarsColor(sysUiController) EmptyAuthEntrySnackBarScreen( authenticationEntryList = getCredentialUiState.providerDisplayInfo.authenticationEntryList, @@ -78,6 +86,7 @@ fun GetCredentialScreen( onLastLockedAuthEntryNotFound = viewModel::onLastLockedAuthEntryNotFoundError, ) } else { + setBottomSheetSystemBarsColor(sysUiController) ModalBottomSheet( sheetContent = { // Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim @@ -173,12 +182,14 @@ fun PrimarySelectionCard( CredentialEntryRow( credentialEntryInfo = it.sortedCredentialEntryList.first(), onEntrySelected = onEntrySelected, + enforceOneLine = true, ) } authenticationEntryList.forEach { AuthenticationEntryRow( authenticationEntryInfo = it, onEntrySelected = onEntrySelected, + enforceOneLine = true, ) } } else if (usernameForCredentialSize < 4) { @@ -186,12 +197,14 @@ fun PrimarySelectionCard( CredentialEntryRow( credentialEntryInfo = it.sortedCredentialEntryList.first(), onEntrySelected = onEntrySelected, + enforceOneLine = true, ) } authenticationEntryList.take(4 - usernameForCredentialSize).forEach { AuthenticationEntryRow( authenticationEntryInfo = it, onEntrySelected = onEntrySelected, + enforceOneLine = true, ) } } else { @@ -199,6 +212,7 @@ fun PrimarySelectionCard( CredentialEntryRow( credentialEntryInfo = it.sortedCredentialEntryList.first(), onEntrySelected = onEntrySelected, + enforceOneLine = true, ) } } @@ -281,13 +295,6 @@ fun AllSignInOptionCard( ) } } - item { - Divider( - thickness = 1.dp, - color = Color.LightGray, - modifier = Modifier.padding(top = 16.dp) - ) - } // Manage sign-ins (action chips) item { ActionChips( @@ -338,7 +345,7 @@ fun RemoteEntryCard( ) { Entry( onClick = { onEntrySelected(remoteEntry) }, - iconPainter = painterResource(R.drawable.ic_other_devices), + iconImageVector = Icons.Outlined.QrCodeScanner, entryHeadlineText = stringResource( R.string.get_dialog_option_headline_use_a_different_device ), @@ -393,28 +400,32 @@ fun PerUserNameCredentials( fun CredentialEntryRow( credentialEntryInfo: CredentialEntryInfo, onEntrySelected: (BaseEntry) -> Unit, + enforceOneLine: Boolean = false, ) { Entry( onClick = { onEntrySelected(credentialEntryInfo) }, iconImageBitmap = credentialEntryInfo.icon?.toBitmap()?.asImageBitmap(), + shouldApplyIconImageBitmapTint = credentialEntryInfo.shouldTintIcon, // Fall back to iconPainter if iconImageBitmap isn't available iconPainter = - if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in) + if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in_24) else null, entryHeadlineText = credentialEntryInfo.userName, entrySecondLineText = if ( credentialEntryInfo.credentialType == CredentialType.PASSWORD) { "••••••••••••" } else { - if (TextUtils.isEmpty(credentialEntryInfo.displayName)) - credentialEntryInfo.credentialTypeDisplayName - else - credentialEntryInfo.credentialTypeDisplayName + - stringResource( - R.string.get_dialog_sign_in_type_username_separator - ) + - credentialEntryInfo.displayName + val itemsToDisplay = listOf( + credentialEntryInfo.displayName, + credentialEntryInfo.credentialTypeDisplayName, + credentialEntryInfo.providerDisplayName + ).filterNot(TextUtils::isEmpty) + if (itemsToDisplay.isEmpty()) null + else itemsToDisplay.joinToString( + separator = stringResource(R.string.get_dialog_sign_in_type_username_separator) + ) }, + enforceOneLine = enforceOneLine, ) } @@ -422,6 +433,7 @@ fun CredentialEntryRow( fun AuthenticationEntryRow( authenticationEntryInfo: AuthenticationEntryInfo, onEntrySelected: (BaseEntry) -> Unit, + enforceOneLine: Boolean = false, ) { Entry( onClick = { onEntrySelected(authenticationEntryInfo) }, @@ -433,6 +445,7 @@ fun AuthenticationEntryRow( else R.string.locked_credential_entry_label_subtext_tap_to_unlock ), isLockedAuthEntry = !authenticationEntryInfo.isUnlockedAndEmpty, + enforceOneLine = enforceOneLine, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index 9727d3f39c4a..263a632ef5ee 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -41,6 +41,23 @@ internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean { !state.requestDisplayInfo.preferImmediatelyAvailableCredentials) } +internal fun findAutoSelectEntry(providerDisplayInfo: ProviderDisplayInfo): CredentialEntryInfo? { + if (providerDisplayInfo.authenticationEntryList.isNotEmpty()) { + return null + } + if (providerDisplayInfo.sortedUserNameToCredentialEntryList.size == 1) { + val entryList = providerDisplayInfo.sortedUserNameToCredentialEntryList.firstOrNull() + ?: return null + if (entryList.sortedCredentialEntryList.size == 1) { + val entry = entryList.sortedCredentialEntryList.firstOrNull() ?: return null + if (entry.isAutoSelectable) { + return entry + } + } + } + return null +} + data class ProviderInfo( /** * Unique id (component name) of this provider. @@ -77,10 +94,13 @@ class CredentialEntryInfo( val credentialType: CredentialType, /** Localized type value of this credential used for display purpose. */ val credentialTypeDisplayName: String, + val providerDisplayName: String, val userName: String, val displayName: String?, val icon: Drawable?, + val shouldTintIcon: Boolean, val lastUsedTimeMillis: Instant?, + val isAutoSelectable: Boolean, ) : BaseEntry( providerId, entryKey, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt b/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt index 120e4938c322..8928e1869838 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt @@ -40,32 +40,8 @@ val LocalAndroidColorScheme = * most of the colors in this class will be removed in favor of their M3 counterpart. */ class AndroidColorScheme internal constructor(context: Context) { - val colorPrimary = getColor(context, R.attr.colorPrimary) - val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark) - val colorAccent = getColor(context, R.attr.colorAccent) - val colorAccentPrimary = getColor(context, R.attr.colorAccentPrimary) - val colorAccentSecondary = getColor(context, R.attr.colorAccentSecondary) - val colorAccentTertiary = getColor(context, R.attr.colorAccentTertiary) - val colorAccentPrimaryVariant = getColor(context, R.attr.colorAccentPrimaryVariant) - val colorAccentSecondaryVariant = getColor(context, R.attr.colorAccentSecondaryVariant) - val colorAccentTertiaryVariant = getColor(context, R.attr.colorAccentTertiaryVariant) - val colorSurface = getColor(context, R.attr.colorSurface) - val colorSurfaceHighlight = getColor(context, R.attr.colorSurfaceHighlight) - val colorSurfaceVariant = getColor(context, R.attr.colorSurfaceVariant) - val colorSurfaceHeader = getColor(context, R.attr.colorSurfaceHeader) - val colorError = getColor(context, R.attr.colorError) - val colorBackground = getColor(context, R.attr.colorBackground) - val colorBackgroundFloating = getColor(context, R.attr.colorBackgroundFloating) - val panelColorBackground = getColor(context, R.attr.panelColorBackground) - val textColorPrimary = getColor(context, R.attr.textColorPrimary) - val textColorSecondary = getColor(context, R.attr.textColorSecondary) - val textColorTertiary = getColor(context, R.attr.textColorTertiary) - val textColorPrimaryInverse = getColor(context, R.attr.textColorPrimaryInverse) - val textColorSecondaryInverse = getColor(context, R.attr.textColorSecondaryInverse) - val textColorTertiaryInverse = getColor(context, R.attr.textColorTertiaryInverse) - val textColorOnAccent = getColor(context, R.attr.textColorOnAccent) - val colorForeground = getColor(context, R.attr.colorForeground) - val colorForegroundInverse = getColor(context, R.attr.colorForegroundInverse) + val colorSurfaceBright = getColor(context, R.attr.materialColorSurfaceBright) + val colorSurfaceContainerHigh = getColor(context, R.attr.materialColorSurfaceContainerHigh) companion object { fun getColor(context: Context, attr: Int): Color { diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle index 640aa01f307f..4563b7d75b22 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle +++ b/packages/SettingsLib/Spa/spa/build.gradle @@ -48,11 +48,11 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '11' + jvmTarget = '17' freeCompilerArgs = ["-Xjvm-default=all"] } buildFeatures { diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt index 78df0f27cc6a..ca88f8da63c9 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt @@ -16,6 +16,7 @@ package com.android.settingslib.spa.framework.common +import android.app.settings.SettingsEnums import android.os.Bundle // Defines the category of the log, for quick filter @@ -31,20 +32,21 @@ enum class LogCategory { } // Defines the log events in Spa. -enum class LogEvent { +enum class LogEvent(val action: Int) { // Page related events. - PAGE_ENTER, - PAGE_LEAVE, + PAGE_ENTER(SettingsEnums.PAGE_VISIBLE), + PAGE_LEAVE(SettingsEnums.PAGE_HIDE), // Entry related events. - ENTRY_CLICK, - ENTRY_SWITCH, + ENTRY_CLICK(SettingsEnums.ACTION_SETTINGS_TILE_CLICK), + ENTRY_SWITCH(SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE), } internal const val LOG_DATA_DISPLAY_NAME = "name" -internal const val LOG_DATA_SESSION_NAME = "session" internal const val LOG_DATA_SWITCH_STATUS = "switch" +const val LOG_DATA_SESSION_NAME = "session" + /** * The interface of logger in Spa */ diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt index 2c3c2e003832..d8c35a36d061 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt @@ -22,9 +22,11 @@ import com.android.settingslib.spa.framework.common.SettingsEntry import com.android.settingslib.spa.framework.common.SettingsPage import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory +const val SESSION_UNKNOWN = "unknown" const val SESSION_BROWSE = "browse" const val SESSION_SEARCH = "search" const val SESSION_SLICE = "slice" +const val SESSION_EXTERNAL = "external" const val KEY_DESTINATION = "spaActivityDestination" const val KEY_HIGHLIGHT_ENTRY = "highlightEntry" diff --git a/packages/SettingsLib/Spa/testutils/build.gradle b/packages/SettingsLib/Spa/testutils/build.gradle index 536829e00b65..e7f7db2f1ec0 100644 --- a/packages/SettingsLib/Spa/testutils/build.gradle +++ b/packages/SettingsLib/Spa/testutils/build.gradle @@ -38,11 +38,11 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '11' + jvmTarget = '17' freeCompilerArgs = ["-Xjvm-default=all"] } buildFeatures { diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt index 1a3c0ab67b93..47bf85d8417b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt @@ -19,6 +19,7 @@ package com.android.settingslib.spaprivileged.template.app import android.content.Context import android.content.pm.ApplicationInfo import android.text.format.Formatter +import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState @@ -30,18 +31,26 @@ import com.android.settingslib.spaprivileged.model.app.userHandle import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +private const val TAG = "AppStorageSize" + @Composable fun ApplicationInfo.getStorageSize(): State<String> { val context = LocalContext.current return produceState(initialValue = stringResource(R.string.summary_placeholder)) { withContext(Dispatchers.IO) { - value = Formatter.formatFileSize(context, calculateSizeBytes(context)) + val sizeBytes = calculateSizeBytes(context) + value = if (sizeBytes != null) Formatter.formatFileSize(context, sizeBytes) else "" } } } -private fun ApplicationInfo.calculateSizeBytes(context: Context): Long { +private fun ApplicationInfo.calculateSizeBytes(context: Context): Long? { val storageStatsManager = context.storageStatsManager - val stats = storageStatsManager.queryStatsForPackage(storageUuid, packageName, userHandle) - return stats.codeBytes + stats.dataBytes + return try { + val stats = storageStatsManager.queryStatsForPackage(storageUuid, packageName, userHandle) + stats.codeBytes + stats.dataBytes + } catch (e: Exception) { + Log.w(TAG, "Failed to query stats: $e") + null + } } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt index fcacc34ba881..e3af58702445 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt @@ -20,6 +20,7 @@ import android.app.usage.StorageStats import android.app.usage.StorageStatsManager import android.content.Context import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager.NameNotFoundException import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.test.junit4.createComposeRule @@ -60,9 +61,11 @@ class AppStorageSizeTest { @Before fun setUp() { whenever(context.storageStatsManager).thenReturn(storageStatsManager) - whenever(storageStatsManager.queryStatsForPackage( - app.storageUuid, app.packageName, app.userHandle - )).thenReturn(STATS) + whenever( + storageStatsManager.queryStatsForPackage( + app.storageUuid, app.packageName, app.userHandle + ) + ).thenReturn(STATS) } @Test @@ -78,6 +81,24 @@ class AppStorageSizeTest { composeTestRule.waitUntil { storageSize.value == "120 B" } } + @Test + fun getStorageSize_throwException() { + var storageSize = stateOf("Computing") + whenever( + storageStatsManager.queryStatsForPackage( + app.storageUuid, app.packageName, app.userHandle + ) + ).thenThrow(NameNotFoundException()) + + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + storageSize = app.getStorageSize() + } + } + + composeTestRule.waitUntil { storageSize.value == "" } + } + companion object { private val STATS = StorageStats().apply { codeBytes = 100 diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml index 1907b3e51d68..28f7c50a732a 100644 --- a/packages/SettingsLib/res/values-af/arrays.xml +++ b/packages/SettingsLib/res/values-af/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Het gefiltreer geaktiveer"</item> <item msgid="2779123106632690576">"Geaktiveer"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Opskrifte is gefiltreer"</item> - <item msgid="4818549483446395865">"A2DP-mediapakkette is gefiltreer"</item> - <item msgid="8207123990453243311">"RFCOMM-kanaal is gefiltreer"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Gedeaktiveer"</item> - <item msgid="5884245882825346396">"Wonder"</item> - <item msgid="6569400572915342949">"Opskrif"</item> - <item msgid="1239386221416967664">"Volledige filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (verstek)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 31f50e8fac58..3de581ea3940 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en onthounotas"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Laat toe dat wekkers en onthounotas gestel word"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en onthounotas"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie program toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die program op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie program geskeduleer is, nie werk nie."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie app toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die app op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie app geskeduleer is, nie werk nie."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"skedule, wekker, onthounota, horlosie"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Skakel aan"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Skakel Moenie steur nie aan"</string> diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml index ad0f1edffdbb..c423d3c86ed1 100644 --- a/packages/SettingsLib/res/values-am/arrays.xml +++ b/packages/SettingsLib/res/values-am/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ማጣሪያን አንቃ"</item> <item msgid="2779123106632690576">"ነቅቷል"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ራስጌዎች ተጣርተዋል"</item> - <item msgid="4818549483446395865">"የA2DP ሚዲያ ፓኬቶች ተጣርተዋል"</item> - <item msgid="8207123990453243311">"የRFCOMM ሰርጥ ተጣርቷል"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ተሰናክሏል"</item> - <item msgid="5884245882825346396">"ማጂክ"</item> - <item msgid="6569400572915342949">"የራስጌ ጽሑፍ"</item> - <item msgid="1239386221416967664">"ሙሉ ማጣሪያ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ነባሪ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml index cede18e807ce..cf46a8fdcc7d 100644 --- a/packages/SettingsLib/res/values-ar/arrays.xml +++ b/packages/SettingsLib/res/values-ar/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"تمّ تفعيل التصفية"</item> <item msgid="2779123106632690576">"مفعّل"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"العناوين المفلترة"</item> - <item msgid="4818549483446395865">"حُزم وسائط A2DP مفلترة"</item> - <item msgid="8207123990453243311">"قناة بروتوكول RFCOMM مفلترة"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"حُزم البيانات غير المفعّلة"</item> - <item msgid="5884245882825346396">"سِحري"</item> - <item msgid="6569400572915342949">"العنوان"</item> - <item msgid="1239386221416967664">"فلترة كاملة"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (تلقائي)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml index c52d27e20e1b..284ca122edef 100644 --- a/packages/SettingsLib/res/values-as/arrays.xml +++ b/packages/SettingsLib/res/values-as/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"সক্ষম কৰাবিলাক ফিল্টাৰ কৰা হৈছে"</item> <item msgid="2779123106632690576">"সক্ষম কৰা আছে"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"হেডাৰ ফিল্টাৰ কৰা হৈছে"</item> - <item msgid="4818549483446395865">"A2DP মিডিয়াৰ পেকেট ফিল্টাৰ কৰা হৈছে"</item> - <item msgid="8207123990453243311">"RFCOMM চেনেল ফিল্টাৰ কৰা হৈছে"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"অক্ষম কৰা আছে"</item> - <item msgid="5884245882825346396">"যাদু"</item> - <item msgid="6569400572915342949">"হেডাৰ"</item> - <item msgid="1239386221416967664">"সম্পূৰ্ণ ফিল্টাৰ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ডিফ’ল্ট)"</item> <item msgid="1637054408779685086">"AVRCP ১.৩"</item> diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml index 9605c512aea3..ff0054bfe810 100644 --- a/packages/SettingsLib/res/values-az/arrays.xml +++ b/packages/SettingsLib/res/values-az/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrləmə aktivdir"</item> <item msgid="2779123106632690576">"Aktivdir"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Başlıqlar Filtrlənib"</item> - <item msgid="4818549483446395865">"A2DP Media Paketləri Filtrlənib"</item> - <item msgid="8207123990453243311">"RFCOMM Kanalı Filtrlənib"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Deaktiv"</item> - <item msgid="5884245882825346396">"Sehr"</item> - <item msgid="6569400572915342949">"Başlıq"</item> - <item msgid="1239386221416967664">"Tam Filtr"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Defolt)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml index 618748b7afb9..32071e541bc7 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Omogućeno filtrirano"</item> <item msgid="2779123106632690576">"Omogućeno"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtrirana zaglavlja"</item> - <item msgid="4818549483446395865">"Filtrirani A2DP medijski paketi"</item> - <item msgid="8207123990453243311">"Filtrirani RFCOMM kanal"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Onemogućeno"</item> - <item msgid="5884245882825346396">"Magija"</item> - <item msgid="6569400572915342949">"Zaglavlje"</item> - <item msgid="1239386221416967664">"Potpuni filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (podrazumevano)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml index 117f0b479c0e..a60d35419cf6 100644 --- a/packages/SettingsLib/res/values-be/arrays.xml +++ b/packages/SettingsLib/res/values-be/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Уключана з фільтрацыяй"</item> <item msgid="2779123106632690576">"Уключана"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Адфільтраваны загалоўкі"</item> - <item msgid="4818549483446395865">"Адфільтраваны пакеты мультымедыя A2DP"</item> - <item msgid="8207123990453243311">"Адфільтраваны канал RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Адключана"</item> - <item msgid="5884245882825346396">"Спецыяльная фраза"</item> - <item msgid="6569400572915342949">"Загаловак"</item> - <item msgid="1239386221416967664">"Поўная фільтрацыя"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (стандартная)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml index cf643c815327..d778ca275d81 100644 --- a/packages/SettingsLib/res/values-bg/arrays.xml +++ b/packages/SettingsLib/res/values-bg/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Филтрирането е активирано"</item> <item msgid="2779123106632690576">"Активирано"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Заглавките са филтрирани"</item> - <item msgid="4818549483446395865">"Мултимедийните пакети A2DP са филтрирани"</item> - <item msgid="8207123990453243311">"Каналът RFCOMM е филтриран"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Деактивирано"</item> - <item msgid="5884245882825346396">"Магия"</item> - <item msgid="6569400572915342949">"Заглавка"</item> - <item msgid="1239386221416967664">"Пълен филтър"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (основно)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml index 1a7652d60d5a..dbb738c3d47e 100644 --- a/packages/SettingsLib/res/values-bn/arrays.xml +++ b/packages/SettingsLib/res/values-bn/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ফিল্টার করা চালু আছে"</item> <item msgid="2779123106632690576">"চালু করা আছে"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"হেডার ফিল্টার করা হয়েছে"</item> - <item msgid="4818549483446395865">"A2DP মিডিয়া প্যাকেট ফিল্টার করা হয়েছে"</item> - <item msgid="8207123990453243311">"RFCOMM চ্যানেল ফিল্টার করা হয়েছে"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"বন্ধ করা আছে"</item> - <item msgid="5884245882825346396">"ম্যাজিক"</item> - <item msgid="6569400572915342949">"হেডার"</item> - <item msgid="1239386221416967664">"সম্পূর্ণ ফিল্টার"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ডিফল্ট)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml index 2ab1b79eb7db..740e70478fc3 100644 --- a/packages/SettingsLib/res/values-bs/arrays.xml +++ b/packages/SettingsLib/res/values-bs/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Omogućeno filtrirano"</item> <item msgid="2779123106632690576">"Omogućeno"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtrirana zaglavlja"</item> - <item msgid="4818549483446395865">"Filtrirani A2DP medijski paketi"</item> - <item msgid="8207123990453243311">"Filtrirani RFCOMM kanal"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Onemogućeno"</item> - <item msgid="5884245882825346396">"Magija"</item> - <item msgid="6569400572915342949">"Zaglavlje"</item> - <item msgid="1239386221416967664">"Potpuni filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (zadano)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index e8cabfaf7ae5..1aa8ff38b2fa 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dozvoli postavljanje alarma i podsjetnika"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu koje je ova aplikacija zakazala neće funkcionirati."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu, a koje je ova aplikacija zakazala, neće funkcionirati."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"raspored, alarm, podsjetnik, sat"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Uključi"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Uključi način rada Ne ometaj"</string> diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml index 00a126cee4e4..4e437ba2d4fe 100644 --- a/packages/SettingsLib/res/values-ca/arrays.xml +++ b/packages/SettingsLib/res/values-ca/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Activat amb filtres"</item> <item msgid="2779123106632690576">"Activat"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Capçaleres filtrades"</item> - <item msgid="4818549483446395865">"Paquets multimèdia A2DP filtrats"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrat"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Desactivat"</item> - <item msgid="5884245882825346396">"Màgia"</item> - <item msgid="6569400572915342949">"Capçalera"</item> - <item msgid="1239386221416967664">"Filtre complet"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (predeterminada)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 83b32d4d492e..f14befdcd123 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes i recordatoris"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permet la configuració d\'alarmes i recordatoris"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes i recordatoris"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions a una hora determinada. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programació, alarma, recordatori, rellotge"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activa"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activa el mode No molestis"</string> diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml index a4bd21f503d0..e1a5aefc34b5 100644 --- a/packages/SettingsLib/res/values-cs/arrays.xml +++ b/packages/SettingsLib/res/values-cs/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Povolit filtrované"</item> <item msgid="2779123106632690576">"Zapnuto"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Záhlaví filtrována"</item> - <item msgid="4818549483446395865">"Mediální balíčky A2DP filtrovány"</item> - <item msgid="8207123990453243311">"Kanál RFCOMM filtrován"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Zakázáno"</item> - <item msgid="5884245882825346396">"Komplexní hodnocení"</item> - <item msgid="6569400572915342949">"Záhlaví"</item> - <item msgid="1239386221416967664">"Úplný filtr"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (výchozí)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml index 37da365d339b..03cab2062bd5 100644 --- a/packages/SettingsLib/res/values-da/arrays.xml +++ b/packages/SettingsLib/res/values-da/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtreret er aktiveret"</item> <item msgid="2779123106632690576">"Aktiveret"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Overskrifter filtreret"</item> - <item msgid="4818549483446395865">"A2DP-mediepakker filtreret"</item> - <item msgid="8207123990453243311">"RFCOMM-kanal filtreret"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Deaktiveret"</item> - <item msgid="5884245882825346396">"Magi"</item> - <item msgid="6569400572915342949">"Overskrift"</item> - <item msgid="1239386221416967664">"Fuldt filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (standard)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml index 2241666fb1ef..c5dcc10b0ccb 100644 --- a/packages/SettingsLib/res/values-de/arrays.xml +++ b/packages/SettingsLib/res/values-de/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filter aktiviert"</item> <item msgid="2779123106632690576">"Aktiviert"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Header gefiltert"</item> - <item msgid="4818549483446395865">"A2DP-Medienpakete gefiltert"</item> - <item msgid="8207123990453243311">"RFCOMM-Kanal gefiltert"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Deaktiviert"</item> - <item msgid="5884245882825346396">"Magie"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Vollständig gefiltert"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Standard)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml index 1a824c1b89d3..6486b3d113c2 100644 --- a/packages/SettingsLib/res/values-el/arrays.xml +++ b/packages/SettingsLib/res/values-el/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Ενεργοποιήθηκε το φιλτράρισμα"</item> <item msgid="2779123106632690576">"Ενεργοποιήθηκε"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Φιλτραρισμένες κεφαλίδες"</item> - <item msgid="4818549483446395865">"Φιλτραρισμένα πακέτα μέσων A2DP"</item> - <item msgid="8207123990453243311">"Φιλτραρισμένο κανάλι RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Ανενεργό"</item> - <item msgid="5884245882825346396">"Μαγεία"</item> - <item msgid="6569400572915342949">"Κεφαλίδα"</item> - <item msgid="1239386221416967664">"Πλήρες φίλτρο"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Προεπιλογή)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml index de633860626c..9a7390e5882e 100644 --- a/packages/SettingsLib/res/values-en-rAU/arrays.xml +++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Enabled Filtered"</item> <item msgid="2779123106632690576">"Enabled"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Headers filtered"</item> - <item msgid="4818549483446395865">"A2DP media packets filtered"</item> - <item msgid="8207123990453243311">"RFCOMM channel filtered"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Disabled"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Full filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml index 0af8b4efc216..184d21005cc1 100644 --- a/packages/SettingsLib/res/values-en-rCA/arrays.xml +++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml @@ -64,15 +64,15 @@ <item msgid="2779123106632690576">"Enabled"</item> </string-array> <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Headers Filtered"</item> - <item msgid="4818549483446395865">"A2DP Media Packets Filtered"</item> - <item msgid="8207123990453243311">"RFCOMM Channel Filtered"</item> + <item msgid="195768089203590086">"Leave only ACL headers"</item> + <item msgid="2776218217644557831">"Filter A2DP media packets"</item> + <item msgid="8163235976612675092">"Filter RFCOMM channel"</item> </string-array> <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Disabled"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Full Filter"</item> + <item msgid="3961868665260627524">"Disable"</item> + <item msgid="2505973306504851132">"Fill with string of characters"</item> + <item msgid="5883011000629613855">"Leave only header"</item> + <item msgid="1051534112762023603">"Fully remove"</item> </string-array> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml index de633860626c..9a7390e5882e 100644 --- a/packages/SettingsLib/res/values-en-rGB/arrays.xml +++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Enabled Filtered"</item> <item msgid="2779123106632690576">"Enabled"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Headers filtered"</item> - <item msgid="4818549483446395865">"A2DP media packets filtered"</item> - <item msgid="8207123990453243311">"RFCOMM channel filtered"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Disabled"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Full filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml index de633860626c..9a7390e5882e 100644 --- a/packages/SettingsLib/res/values-en-rIN/arrays.xml +++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Enabled Filtered"</item> <item msgid="2779123106632690576">"Enabled"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Headers filtered"</item> - <item msgid="4818549483446395865">"A2DP media packets filtered"</item> - <item msgid="8207123990453243311">"RFCOMM channel filtered"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Disabled"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Full filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-en-rXC/arrays.xml b/packages/SettingsLib/res/values-en-rXC/arrays.xml index 30c9a4968997..dec70f456d1e 100644 --- a/packages/SettingsLib/res/values-en-rXC/arrays.xml +++ b/packages/SettingsLib/res/values-en-rXC/arrays.xml @@ -64,15 +64,15 @@ <item msgid="2779123106632690576">"Enabled"</item> </string-array> <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Headers Filtered"</item> - <item msgid="4818549483446395865">"A2DP Media Packets Filtered"</item> - <item msgid="8207123990453243311">"RFCOMM Channel Filtered"</item> + <item msgid="195768089203590086">"Leave only ACL headers"</item> + <item msgid="2776218217644557831">"Filter A2DP media packets"</item> + <item msgid="8163235976612675092">"Filter RFCOMM channel"</item> </string-array> <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Disabled"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Full Filter"</item> + <item msgid="3961868665260627524">"Disable"</item> + <item msgid="2505973306504851132">"Fill with string of characters"</item> + <item msgid="5883011000629613855">"Leave only header"</item> + <item msgid="1051534112762023603">"Fully remove"</item> </string-array> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml index e2a36c6fa255..771690dc8309 100644 --- a/packages/SettingsLib/res/values-es-rUS/arrays.xml +++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrado habilitado"</item> <item msgid="2779123106632690576">"Habilitado"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Títulos filtrados"</item> - <item msgid="4818549483446395865">"Paquetes de medios A2DP filtrados"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrado"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Inhabilitada"</item> - <item msgid="5884245882825346396">"Automático"</item> - <item msgid="6569400572915342949">"Título"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (predeterminado)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml index b5e035c9cd2f..e07f9dc372f7 100644 --- a/packages/SettingsLib/res/values-es/arrays.xml +++ b/packages/SettingsLib/res/values-es/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Habilitado con filtros"</item> <item msgid="2779123106632690576">"Habilitado"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Encabezados filtrados"</item> - <item msgid="4818549483446395865">"Paquetes de medios A2DP filtrados"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrado"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Inhabilitado"</item> - <item msgid="5884245882825346396">"Mágico"</item> - <item msgid="6569400572915342949">"Encabezado"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (predeterminado)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml index d910a0ed58c9..34448a72525e 100644 --- a/packages/SettingsLib/res/values-et/arrays.xml +++ b/packages/SettingsLib/res/values-et/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Luba filtreeritud"</item> <item msgid="2779123106632690576">"Lubatud"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtreeritud päised"</item> - <item msgid="4818549483446395865">"Filtreeritud A2DP meediapaketid"</item> - <item msgid="8207123990453243311">"Filtreeritud RFCOMM-kanal"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Keelatud"</item> - <item msgid="5884245882825346396">"Maagiline"</item> - <item msgid="6569400572915342949">"Päis"</item> - <item msgid="1239386221416967664">"Täielik filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (vaikeseade)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml index 2d3575b0f828..eb678ffc03e3 100644 --- a/packages/SettingsLib/res/values-eu/arrays.xml +++ b/packages/SettingsLib/res/values-eu/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Gaituta baina iragazita"</item> <item msgid="2779123106632690576">"Gaituta"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Goiburuan iragazita"</item> - <item msgid="4818549483446395865">"A2DP multimedia-paketeak iragazita"</item> - <item msgid="8207123990453243311">"RFCOMM kanala iragazita"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Desgaituta"</item> - <item msgid="5884245882825346396">"Magia"</item> - <item msgid="6569400572915342949">"Goiburua"</item> - <item msgid="1239386221416967664">"Iragazki osoa"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (lehenetsia)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 82e0eea0167f..02ab1920731d 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmak eta abisuak"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Eman alarmak eta abisuak ezartzeko baimena"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nEz baduzu ematen baimen hori, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nBaimen hori ematen ez baduzu, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programazioa, alarma, abisua, erlojua"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktibatu"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktibatu ez molestatzeko modua"</string> diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml index b983bcc51bdf..2d9be3177a16 100644 --- a/packages/SettingsLib/res/values-fa/arrays.xml +++ b/packages/SettingsLib/res/values-fa/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"فیلترشده فعال شده است"</item> <item msgid="2779123106632690576">"فعال"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"سرصفحهها فیلتر شد"</item> - <item msgid="4818549483446395865">"بستههای رسانه A2DP فیلتر شد"</item> - <item msgid="8207123990453243311">"کانال RFCOMM فیلتر شد"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"غیرفعال"</item> - <item msgid="5884245882825346396">"جادویی"</item> - <item msgid="6569400572915342949">"سرصفحه"</item> - <item msgid="1239386221416967664">"فیلتر کامل"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP نسخه ۱.۵ (پیشفرض)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml index 9e3bcd238ae9..d6f002f5b539 100644 --- a/packages/SettingsLib/res/values-fi/arrays.xml +++ b/packages/SettingsLib/res/values-fi/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Suodatus käytössä"</item> <item msgid="2779123106632690576">"Päällä"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Otsikot suodatettu"</item> - <item msgid="4818549483446395865">"A2DP-mediapaketit suodatettu"</item> - <item msgid="8207123990453243311">"RFCOMM-kanava suodatettu"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Ei käytössä"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Otsikko"</item> - <item msgid="1239386221416967664">"Täysi suodatus"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (oletus)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml index 86066b6a6714..6657aa121159 100644 --- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml +++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtres activés"</item> <item msgid="2779123106632690576">"Activé"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"En-têtes filtrés"</item> - <item msgid="4818549483446395865">"Paquets multimédias A2DP filtrés"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtré"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Désactivé"</item> - <item msgid="5884245882825346396">"Magie"</item> - <item msgid="6569400572915342949">"En-tête"</item> - <item msgid="1239386221416967664">"Filtre intégral"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (par défaut)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml index 5f31ff5e8dcd..869d88ad5599 100644 --- a/packages/SettingsLib/res/values-fr/arrays.xml +++ b/packages/SettingsLib/res/values-fr/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Activé et filtré"</item> <item msgid="2779123106632690576">"Activé"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"En-têtes filtrés"</item> - <item msgid="4818549483446395865">"Paquets multimédias A2DP filtrés"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtré"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Désactivé"</item> - <item msgid="5884245882825346396">"Magie"</item> - <item msgid="6569400572915342949">"En-tête"</item> - <item msgid="1239386221416967664">"Filtre complet"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (par défaut)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml index 665851db60e8..3cd7b4b4c4a0 100644 --- a/packages/SettingsLib/res/values-gl/arrays.xml +++ b/packages/SettingsLib/res/values-gl/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Está activado o filtrado"</item> <item msgid="2779123106632690576">"Activada"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Cabeceiras filtradas"</item> - <item msgid="4818549483446395865">"A2DP Media Packets filtrados"</item> - <item msgid="8207123990453243311">"Canle RFCOMM filtrada"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Desactivado"</item> - <item msgid="5884245882825346396">"Maxia"</item> - <item msgid="6569400572915342949">"Cabeceira"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (predeterminado)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml index e3739521b9d2..f559b805af4c 100644 --- a/packages/SettingsLib/res/values-gu/arrays.xml +++ b/packages/SettingsLib/res/values-gu/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ફિલ્ટર કરેલ ચાલુ છે"</item> <item msgid="2779123106632690576">"ચાલુ છે"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ફિલ્ટર કરેલા હેડર"</item> - <item msgid="4818549483446395865">"ફિલ્ટર કરેલા A2DP મીડિયા પૅકેટ"</item> - <item msgid="8207123990453243311">"ફિલ્ટર કરેલી RFCOMM ચૅનલ"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"બંધ કર્યું"</item> - <item msgid="5884245882825346396">"જાદુ"</item> - <item msgid="6569400572915342949">"હેડર"</item> - <item msgid="1239386221416967664">"સંપૂર્ણ ફિલ્ટર"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ડિફૉલ્ટ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml index 356a13c3320a..be8862096de8 100644 --- a/packages/SettingsLib/res/values-hi/arrays.xml +++ b/packages/SettingsLib/res/values-hi/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"चालू और फ़िल्टर किया गया"</item> <item msgid="2779123106632690576">"चालू है"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"हेडर फ़िल्टर किए गए"</item> - <item msgid="4818549483446395865">"A2DP मीडिया पैकेट फ़िल्टर किए गए"</item> - <item msgid="8207123990453243311">"RFCOMM चैनल फ़िल्टर किए गए"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"बंद है"</item> - <item msgid="5884245882825346396">"मैजिक"</item> - <item msgid="6569400572915342949">"हेडर"</item> - <item msgid="1239386221416967664">"सभी फ़िल्टर"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (डिफ़ॉल्ट)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml index 812f8d270d33..5c73ebba1402 100644 --- a/packages/SettingsLib/res/values-hr/arrays.xml +++ b/packages/SettingsLib/res/values-hr/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Omogućeno filtrirano"</item> <item msgid="2779123106632690576">"Omogućeno"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtrirana zaglavlja"</item> - <item msgid="4818549483446395865">"Filtrirani A2DP medijski paketi"</item> - <item msgid="8207123990453243311">"Filtrirani RFCOMM kanal"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Onemogućeno"</item> - <item msgid="5884245882825346396">"Čarolija"</item> - <item msgid="6569400572915342949">"Zaglavlje"</item> - <item msgid="1239386221416967664">"Potpuni filtar"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (zadano)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml index 9c842f997a10..500b9fd228f3 100644 --- a/packages/SettingsLib/res/values-hu/arrays.xml +++ b/packages/SettingsLib/res/values-hu/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Szűrtek engedélyezve"</item> <item msgid="2779123106632690576">"Engedélyezve"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Szűrt fejlécek"</item> - <item msgid="4818549483446395865">"Szűrt A2DP-médiacsomagok"</item> - <item msgid="8207123990453243311">"Szűrt RFCOMM-csatorna"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Kikapcsolva"</item> - <item msgid="5884245882825346396">"Mágia"</item> - <item msgid="6569400572915342949">"Fejléc"</item> - <item msgid="1239386221416967664">"Teljes szűrő"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (alapértelmezett)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml index 59351c4520e6..6fd6893b83e6 100644 --- a/packages/SettingsLib/res/values-hy/arrays.xml +++ b/packages/SettingsLib/res/values-hy/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Միացված է զտիչներով"</item> <item msgid="2779123106632690576">"Միացված է"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Զտված էջագլուխներ"</item> - <item msgid="4818549483446395865">"Զտված A2DP մուլտիմեդիա փաթեթներ"</item> - <item msgid="8207123990453243311">"Զտված RFCOMM կապուղի"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Անջատված է"</item> - <item msgid="5884245882825346396">"Կախարդանք"</item> - <item msgid="6569400572915342949">"Էջագլուխ"</item> - <item msgid="1239386221416967664">"Ամբողջական զտիչ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (կանխադրված)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml index 06e24b904844..8257d0ee983a 100644 --- a/packages/SettingsLib/res/values-in/arrays.xml +++ b/packages/SettingsLib/res/values-in/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Diaktifkan Difilter"</item> <item msgid="2779123106632690576">"Diaktifkan"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Header Difilter"</item> - <item msgid="4818549483446395865">"Paket Media A2DP Difilter"</item> - <item msgid="8207123990453243311">"Saluran RFCOMM Difilter"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Nonaktif"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Filter Lengkap"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml index a87e760a800e..1b114eeaff93 100644 --- a/packages/SettingsLib/res/values-is/arrays.xml +++ b/packages/SettingsLib/res/values-is/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Kveikt á síuðu"</item> <item msgid="2779123106632690576">"Kveikt"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Síaðar fyrirsagnir"</item> - <item msgid="4818549483446395865">"Síaðir A2DP-efnispakkar"</item> - <item msgid="8207123990453243311">"Síuð RFCOMM-rás"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Slökkt"</item> - <item msgid="5884245882825346396">"Töfrar"</item> - <item msgid="6569400572915342949">"Haus"</item> - <item msgid="1239386221416967664">"Heildarsía"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (sjálfgefið)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml index 18923b6899c4..50eca9304321 100644 --- a/packages/SettingsLib/res/values-it/arrays.xml +++ b/packages/SettingsLib/res/values-it/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtro attivo"</item> <item msgid="2779123106632690576">"Attiva"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Intestazioni filtrate"</item> - <item msgid="4818549483446395865">"Pacchetti multimediali A2DP filtrati"</item> - <item msgid="8207123990453243311">"Canale RFCOMM filtrato"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Disattivato"</item> - <item msgid="5884245882825346396">"Magia"</item> - <item msgid="6569400572915342949">"Intestazione"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (versione predefinita)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml index 8e76f2e32e32..02b77516ed3b 100644 --- a/packages/SettingsLib/res/values-iw/arrays.xml +++ b/packages/SettingsLib/res/values-iw/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"המסננים המופעלים"</item> <item msgid="2779123106632690576">"מופעל"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"כותרות לאחר סינון"</item> - <item msgid="4818549483446395865">"מנות מדיה A2DP לאחר סינון"</item> - <item msgid="8207123990453243311">"ערוצי RFCOMM לאחר סינון"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"בהשבתה"</item> - <item msgid="5884245882825346396">"קסם"</item> - <item msgid="6569400572915342949">"כותרת"</item> - <item msgid="1239386221416967664">"סינון מלא"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ברירת המחדל)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml index 47517fef6d60..869fd9970065 100644 --- a/packages/SettingsLib/res/values-ja/arrays.xml +++ b/packages/SettingsLib/res/values-ja/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"有効(フィルタ済み)"</item> <item msgid="2779123106632690576">"有効"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ヘッダーのフィルタ"</item> - <item msgid="4818549483446395865">"A2DP メディア パケットのフィルタ"</item> - <item msgid="8207123990453243311">"RFCOMM チャネルのフィルタ"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"無効"</item> - <item msgid="5884245882825346396">"マジック"</item> - <item msgid="6569400572915342949">"ヘッダー"</item> - <item msgid="1239386221416967664">"フルフィルタ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5(デフォルト)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml index eceaac76c86c..71a283c9a848 100644 --- a/packages/SettingsLib/res/values-ka/arrays.xml +++ b/packages/SettingsLib/res/values-ka/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"გაფილტრულის ჩართვა"</item> <item msgid="2779123106632690576">"ჩართულია"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"გაფილტრული სათაურები"</item> - <item msgid="4818549483446395865">"გაფილტრული A2DP მედია პაკეტები"</item> - <item msgid="8207123990453243311">"გაფილტრული RFCOMM არხი"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"გათიშული"</item> - <item msgid="5884245882825346396">"მაგია"</item> - <item msgid="6569400572915342949">"სათაური"</item> - <item msgid="1239386221416967664">"სრული ფილტრი"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ნაგულისხმევი)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml index 517b1168037f..ab5e10763b7b 100644 --- a/packages/SettingsLib/res/values-kk/arrays.xml +++ b/packages/SettingsLib/res/values-kk/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Сүзгіленгендері қосулы"</item> <item msgid="2779123106632690576">"Қосулы"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Сүзілген тақырыптар"</item> - <item msgid="4818549483446395865">"Сүзілген A2DP медиапакеттері"</item> - <item msgid="8207123990453243311">"Сүзілген RFCOMM арнасы"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Өшірулі"</item> - <item msgid="5884245882825346396">"Сиқыр"</item> - <item msgid="6569400572915342949">"Тақырып"</item> - <item msgid="1239386221416967664">"Толық сүзгі"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (әдепкі)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml index db993294a8a1..bfc983457f5a 100644 --- a/packages/SettingsLib/res/values-km/arrays.xml +++ b/packages/SettingsLib/res/values-km/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"បានបើកការត្រង"</item> <item msgid="2779123106632690576">"បានបើក"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"បានត្រងក្បាលទំព័រ"</item> - <item msgid="4818549483446395865">"បានត្រងកញ្ចប់មេឌៀ A2DP"</item> - <item msgid="8207123990453243311">"បានត្រងបណ្ដាញ RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"បានបិទ"</item> - <item msgid="5884245882825346396">"វេទមន្ត"</item> - <item msgid="6569400572915342949">"ក្បាលទំព័រ"</item> - <item msgid="1239386221416967664">"តម្រងពេញ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (លំនាំដើម)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml index 2bf4ef011a8e..61e27912dda8 100644 --- a/packages/SettingsLib/res/values-kn/arrays.xml +++ b/packages/SettingsLib/res/values-kn/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ಫಿಲ್ಟರ್ ಮಾಡುವುದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</item> <item msgid="2779123106632690576">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ಶಿರೋಲೇಖಗಳನ್ನು ಫಿಲ್ಟರ್ ಮಾಡಲಾಗಿದೆ"</item> - <item msgid="4818549483446395865">"A2DP ಮೀಡಿಯಾ ಪ್ಯಾಕೆಟ್ಗಳನ್ನು ಫಿಲ್ಟರ್ ಮಾಡಲಾಗಿದೆ"</item> - <item msgid="8207123990453243311">"RFCOMM ಚಾನಲ್ ಫಿಲ್ಟರ್ ಮಾಡಲಾಗಿದೆ"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</item> - <item msgid="5884245882825346396">"ಮ್ಯಾಜಿಕ್"</item> - <item msgid="6569400572915342949">"ಶಿರೋಲೇಖ"</item> - <item msgid="1239386221416967664">"ಸಂಪೂರ್ಣ ಫಿಲ್ಟರ್"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ಡೀಫಾಲ್ಟ್)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml index 1a1469f862fa..b4a035ae2751 100644 --- a/packages/SettingsLib/res/values-ko/arrays.xml +++ b/packages/SettingsLib/res/values-ko/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"필터링 사용 설정됨"</item> <item msgid="2779123106632690576">"사용 설정됨"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"헤더 필터링됨"</item> - <item msgid="4818549483446395865">"A2DP 미디어 패킷 필터링됨"</item> - <item msgid="8207123990453243311">"RFCOMM 채널 필터링됨"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"사용 안함"</item> - <item msgid="5884245882825346396">"매직"</item> - <item msgid="6569400572915342949">"헤더"</item> - <item msgid="1239386221416967664">"전체 필터"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5(기본값)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml index f59d4d4ec2f5..657e63ea33b5 100644 --- a/packages/SettingsLib/res/values-ky/arrays.xml +++ b/packages/SettingsLib/res/values-ky/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Чыпкалар иштетилди"</item> <item msgid="2779123106632690576">"Иштетилди"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Жогорку колонтитулдар чыпкаланды"</item> - <item msgid="4818549483446395865">"A2DP медиа топтомдор чыпкаланды"</item> - <item msgid="8207123990453243311">"RFCOMM каналы чыпкаланды"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Өчүрүлдү"</item> - <item msgid="5884245882825346396">"Сыйкырдуу"</item> - <item msgid="6569400572915342949">"Жогорку колонтитул"</item> - <item msgid="1239386221416967664">"Толук чыпка"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Демейки)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml index 4981273e7712..11688d4dfb04 100644 --- a/packages/SettingsLib/res/values-lo/arrays.xml +++ b/packages/SettingsLib/res/values-lo/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ເປີດການກັ່ນຕອງແລ້ວ"</item> <item msgid="2779123106632690576">"ເປີດໃຊ້ແລ້ວ"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ສ່ວນຫົວຖືກກັ່ນຕອງ"</item> - <item msgid="4818549483446395865">"ແພັກເກດສື່ A2DP ຖືກກັ່ນຕອງ"</item> - <item msgid="8207123990453243311">"ຊ່ອງ RFCOMM ຖືກກັ່ນຕອງ"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ປິດການນຳໃຊ້ແລ້ວ"</item> - <item msgid="5884245882825346396">"ເວດມົນ"</item> - <item msgid="6569400572915342949">"ສ່ວນຫົວ"</item> - <item msgid="1239386221416967664">"ການກັ່ນຕອງແບບເຕັມ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ຄ່າເລີ່ມຕົ້ນ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml index 15e65e85f250..6718660be334 100644 --- a/packages/SettingsLib/res/values-lt/arrays.xml +++ b/packages/SettingsLib/res/values-lt/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Įgalinta filtruota"</item> <item msgid="2779123106632690576">"Įgalinta"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Antraštės išfiltruotos"</item> - <item msgid="4818549483446395865">"A2DP medijos paketai išfiltruoti"</item> - <item msgid="8207123990453243311">"RFCOMM kanalas išfiltruotas"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Išjungta"</item> - <item msgid="5884245882825346396">"Magiškoji eilutė"</item> - <item msgid="6569400572915342949">"Antraštė"</item> - <item msgid="1239386221416967664">"Visi filtrai"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (numatytoji)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml index 47531a00b503..3e1869abd3de 100644 --- a/packages/SettingsLib/res/values-lv/arrays.xml +++ b/packages/SettingsLib/res/values-lv/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Iespējot filtrētos"</item> <item msgid="2779123106632690576">"Iespējots"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtrētas galvenes"</item> - <item msgid="4818549483446395865">"Filtrētas A2DP multivides paketes"</item> - <item msgid="8207123990453243311">"Filtrēts RFCOMM kanāls"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Atspējots"</item> - <item msgid="5884245882825346396">"Pielāgotās virknes"</item> - <item msgid="6569400572915342949">"Galvene"</item> - <item msgid="1239386221416967664">"Visi filtri"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (noklusējums)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml index 9d5a5e1d3e2a..ebf387badec7 100644 --- a/packages/SettingsLib/res/values-mk/arrays.xml +++ b/packages/SettingsLib/res/values-mk/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Овозможено е филтрирано"</item> <item msgid="2779123106632690576">"Овозможено"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Насловите се филтрирани"</item> - <item msgid="4818549483446395865">"A2DP аудиовизуелните пакети се филтрирани"</item> - <item msgid="8207123990453243311">"RFCOMM-каналот е филтриран"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Оневозможено"</item> - <item msgid="5884245882825346396">"Магија"</item> - <item msgid="6569400572915342949">"Заглавие"</item> - <item msgid="1239386221416967664">"Целосен филтер"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Стандардна)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml index f28be85d4cb1..30adb57365aa 100644 --- a/packages/SettingsLib/res/values-ml/arrays.xml +++ b/packages/SettingsLib/res/values-ml/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ഫിൽട്ടറിംഗ് പ്രവർത്തനക്ഷമമാക്കി"</item> <item msgid="2779123106632690576">"പ്രവർത്തനക്ഷമമാക്കി"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ഹെഡ്ഡറുകൾ ഫിൽട്ടർ ചെയ്തു"</item> - <item msgid="4818549483446395865">"A2DP മീഡിയാ പാക്കറ്റകൾ ഫിൽട്ടർ ചെയ്തു"</item> - <item msgid="8207123990453243311">"RFCOMM ചാനൽ ഫിൽട്ടർ ചെയ്തു"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"പ്രവർത്തനരഹിതമാക്കി"</item> - <item msgid="5884245882825346396">"മാജിക്"</item> - <item msgid="6569400572915342949">"ഹെഡ്ഡർ"</item> - <item msgid="1239386221416967664">"പൂർണ്ണ ഫിൽട്ടർ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ഡിഫോൾട്ട്)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml index d3c344eb8a9e..d03fcd651586 100644 --- a/packages/SettingsLib/res/values-mn/arrays.xml +++ b/packages/SettingsLib/res/values-mn/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Идэвхжүүлсэн Шүүсэн"</item> <item msgid="2779123106632690576">"Идэвхжүүлсэн"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Толгой хэсгийг шүүсэн"</item> - <item msgid="4818549483446395865">"A2DP Медиа пакетыг шүүсэн"</item> - <item msgid="8207123990453243311">"RFCOMM сувгийг шүүсэн"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Идэвхгүй болгосон"</item> - <item msgid="5884245882825346396">"Ид шид"</item> - <item msgid="6569400572915342949">"Толгой хэсэг"</item> - <item msgid="1239386221416967664">"Бүтэн шүүлтүүр"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Өгөгдмөл)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml index 093e36baa99b..68eff756451f 100644 --- a/packages/SettingsLib/res/values-mr/arrays.xml +++ b/packages/SettingsLib/res/values-mr/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"फिल्टर केलेले सुरू केले"</item> <item msgid="2779123106632690576">"सुरू केले"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"फिल्टर केलेले हेडर"</item> - <item msgid="4818549483446395865">"फिल्टर केलेली A2DP मीडिया पॅकेट"</item> - <item msgid="8207123990453243311">"फिल्टर केलेली RFCOMM चॅनल"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"बंद केले"</item> - <item msgid="5884245882825346396">"मॅजिक"</item> - <item msgid="6569400572915342949">"हेडर"</item> - <item msgid="1239386221416967664">"पूर्ण फिल्टर"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (डीफॉल्ट)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml index 1daa57982d97..efdd879638cb 100644 --- a/packages/SettingsLib/res/values-ms/arrays.xml +++ b/packages/SettingsLib/res/values-ms/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Didayakan Ditapis"</item> <item msgid="2779123106632690576">"Didayakan"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Pengepala Ditapis"</item> - <item msgid="4818549483446395865">"Paket Media A2DP Ditapis"</item> - <item msgid="8207123990453243311">"Saluran RFCOMM Ditapis"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Dilumpuhkan"</item> - <item msgid="5884245882825346396">"Magik"</item> - <item msgid="6569400572915342949">"Pengepala"</item> - <item msgid="1239386221416967664">"Penapis Penuh"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Lalai)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml index dbca2993c781..4d0b792a8532 100644 --- a/packages/SettingsLib/res/values-my/arrays.xml +++ b/packages/SettingsLib/res/values-my/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"စစ်ထုတ်ထားသည်များကို ဖွင့်ထားသည်"</item> <item msgid="2779123106632690576">"ဖွင့်ထားသည်"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"စစ်ထုတ်ထားသော ခေါင်းစီးများ"</item> - <item msgid="4818549483446395865">"စစ်ထုတ်ထားသော A2DP မီဒီယာအတွဲများ"</item> - <item msgid="8207123990453243311">"စစ်ထုတ်ထားသော RFCOMM ချန်နယ်"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ပိတ်ထားသည်"</item> - <item msgid="5884245882825346396">"ပဉ္စလက်"</item> - <item msgid="6569400572915342949">"ခေါင်းစီး"</item> - <item msgid="1239386221416967664">"စစ်ထုတ်မှုအပြည့်"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (မူလ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml index 35c4cdd9fa41..9293bdadb02d 100644 --- a/packages/SettingsLib/res/values-nb/arrays.xml +++ b/packages/SettingsLib/res/values-nb/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrering er slått på"</item> <item msgid="2779123106632690576">"Slått på"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtrert topptekst"</item> - <item msgid="4818549483446395865">"Filtrerte A2DP-mediepakker"</item> - <item msgid="8207123990453243311">"Filtrert RFCOMM-kanal"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Slått av"</item> - <item msgid="5884245882825346396">"Magi"</item> - <item msgid="6569400572915342949">"Topptekst"</item> - <item msgid="1239386221416967664">"Fullt filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (standard)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml index 76652cd8ea6e..29a7c6017510 100644 --- a/packages/SettingsLib/res/values-ne/arrays.xml +++ b/packages/SettingsLib/res/values-ne/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"फिल्टर सक्षम पारियो"</item> <item msgid="2779123106632690576">"सक्षम पारिएको छ"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"हेडरहरू फिल्टर गरिए"</item> - <item msgid="4818549483446395865">"A2DP मिडिया प्याकेटहरू फिल्टर गरिए"</item> - <item msgid="8207123990453243311">"RFCOMM च्यानल फिल्टर गरियो"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"अफ गरियो"</item> - <item msgid="5884245882825346396">"म्याजिक"</item> - <item msgid="6569400572915342949">"हेडर"</item> - <item msgid="1239386221416967664">"फुल फिल्टर"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP १.५ (डिफल्ट)"</item> <item msgid="1637054408779685086">"AVRCP १.३"</item> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index ae7e8b3ec4d3..831ed2f24082 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -520,7 +520,7 @@ <string name="okay" msgid="949938843324579502">"ठिक छ"</string> <string name="done" msgid="381184316122520313">"सम्पन्न भयो"</string> <string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string> - <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिइयोस्"</string> + <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्ने अनुमति दिनुहोस्"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म तथा रिमाइन्डर"</string> <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"यो एपलाई अलार्म सेट गर्ने र समयमै पूरा गर्नु पर्ने कारबाहीहरूको रुटिन बनाउने अनुमति दिनुहोस्। यो अनुमति दिइएको छ भने यो एप ब्याकग्राउन्डमा चल्छ र धेरै ब्याट्री खपत हुन्छ।\n\nयो अनुमति दिइएको छैन भने सेट गरिएका अलार्म बज्दैनन् र यो एपले तय गरेका गतिविधि चल्दैनन्।"</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"समयतालिका, अलार्म, रिमाइन्डर, घडी"</string> diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml index 2ecfbd844492..460302cfb29d 100644 --- a/packages/SettingsLib/res/values-nl/arrays.xml +++ b/packages/SettingsLib/res/values-nl/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Gefilterd staat aan"</item> <item msgid="2779123106632690576">"Aangezet"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Headers gefilterd"</item> - <item msgid="4818549483446395865">"A2DP-mediapakketten gefilterd"</item> - <item msgid="8207123990453243311">"RFCOMM-kanaal gefilterd"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Uitgezet"</item> - <item msgid="5884245882825346396">"Magie"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Volledig filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (standaard)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml index 5f483445afa0..439bd725004b 100644 --- a/packages/SettingsLib/res/values-or/arrays.xml +++ b/packages/SettingsLib/res/values-or/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ଫିଲ୍ଟର୍କୁ ସକ୍ଷମ କରାଯାଇଛି"</item> <item msgid="2779123106632690576">"ସକ୍ଷମ କରାଯାଇଛି"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ହେଡରଗୁଡ଼ିକୁ ଫିଲ୍ଟର କରାଯାଇଛି"</item> - <item msgid="4818549483446395865">"A2DP ମିଡିଆ ପେକେଟ ଫିଲ୍ଟର କରାଯାଇଛି"</item> - <item msgid="8207123990453243311">"RFCOMM ଚେନେଲ ଫିଲ୍ଟର କରାଯାଇଛି"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ଅକ୍ଷମ କରାଯାଇଛି"</item> - <item msgid="5884245882825346396">"ମେଜିକ"</item> - <item msgid="6569400572915342949">"ହେଡର"</item> - <item msgid="1239386221416967664">"ସମ୍ପୂର୍ଣ୍ଣ ଫିଲ୍ଟର"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ଡିଫଲ୍ଟ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml index d8b1c7e5937d..f4bfcd1f1861 100644 --- a/packages/SettingsLib/res/values-pa/arrays.xml +++ b/packages/SettingsLib/res/values-pa/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ਫਿਲਟਰ ਕੀਤਿਆਂ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</item> <item msgid="2779123106632690576">"ਚਾਲੂ"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ਸਿਰਲੇਖ ਫਿਲਟਰ ਕੀਤੇ ਗਏ"</item> - <item msgid="4818549483446395865">"A2DP ਮੀਡੀਆ ਪੈਕੇਟ ਫਿਲਟਰ ਕੀਤੇ ਗਏ"</item> - <item msgid="8207123990453243311">"RFCOMM ਚੈਨਲ ਫਿਲਟਰ ਕੀਤੇ ਗਏ"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ਬੰਦ ਹੈ"</item> - <item msgid="5884245882825346396">"ਜਾਦੂ"</item> - <item msgid="6569400572915342949">"ਸਿਰਲੇਖ"</item> - <item msgid="1239386221416967664">"ਸਭ ਫਿਲਟਰ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml index 9659acb0f88f..a305a65c16cd 100644 --- a/packages/SettingsLib/res/values-pl/arrays.xml +++ b/packages/SettingsLib/res/values-pl/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrowanie włączone"</item> <item msgid="2779123106632690576">"Włączono"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Przefiltrowane nagłówki"</item> - <item msgid="4818549483446395865">"Przefiltrowane pakiety multimediów A2DP"</item> - <item msgid="8207123990453243311">"Przefiltrowany kanał RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Wyłączono"</item> - <item msgid="5884245882825346396">"Magia"</item> - <item msgid="6569400572915342949">"Nagłówek"</item> - <item msgid="1239386221416967664">"Pełny filtr"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (domyślnie)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 84aa66aa3963..ddff92c78b26 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmy i przypomnienia"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Zezwalaj na ustawianie alarmów i przypomnień"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmy i przypomnienia"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwól na ustawianie alarmów i planowanie innych działań, w przypadku których czas jest istotny. Dzięki temu aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tych uprawnień, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwalaj tej aplikacji na ustawianie alarmów i planowanie działań, w przypadku których czas jest istotny. Aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tego uprawnienia, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"harmonogram, alarm, przypomnienie, zegar"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Włącz"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Włącz tryb Nie przeszkadzać"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml index 0bff6c781687..eff092216c0a 100644 --- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml +++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtro ativado"</item> <item msgid="2779123106632690576">"Ativado"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Cabeçalhos filtrados"</item> - <item msgid="4818549483446395865">"Pacotes de mídia A2DP filtrados"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrado"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Desativado"</item> - <item msgid="5884245882825346396">"Mágica"</item> - <item msgid="6569400572915342949">"Cabeçalho"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (padrão)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 168207d518df..3a48c3d2b6a5 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações mais imediatas. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml index b134be6d9ead..0553aac032e8 100644 --- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml +++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrado ativado"</item> <item msgid="2779123106632690576">"Ativado"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Cabeçalhos filtrados"</item> - <item msgid="4818549483446395865">"Pacotes de multimédia A2DP filtrados"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrado"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Desativado"</item> - <item msgid="5884245882825346396">"Magia"</item> - <item msgid="6569400572915342949">"Cabeçalho"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (predefinição)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml index 0bff6c781687..eff092216c0a 100644 --- a/packages/SettingsLib/res/values-pt/arrays.xml +++ b/packages/SettingsLib/res/values-pt/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtro ativado"</item> <item msgid="2779123106632690576">"Ativado"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Cabeçalhos filtrados"</item> - <item msgid="4818549483446395865">"Pacotes de mídia A2DP filtrados"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrado"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Desativado"</item> - <item msgid="5884245882825346396">"Mágica"</item> - <item msgid="6569400572915342949">"Cabeçalho"</item> - <item msgid="1239386221416967664">"Filtro completo"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (padrão)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 168207d518df..3a48c3d2b6a5 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações mais imediatas. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string> diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml index 8c7ffb20fc79..303d669c4eae 100644 --- a/packages/SettingsLib/res/values-ro/arrays.xml +++ b/packages/SettingsLib/res/values-ro/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Este activat Filtrat"</item> <item msgid="2779123106632690576">"Activat"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Anteturi filtrate"</item> - <item msgid="4818549483446395865">"Pachete media A2DP filtrate"</item> - <item msgid="8207123990453243311">"Canal RFCOMM filtrat"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Dezactivat"</item> - <item msgid="5884245882825346396">"Magie"</item> - <item msgid="6569400572915342949">"Antet"</item> - <item msgid="1239386221416967664">"Filtru complet"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (prestabilit)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index dba7507b090d..e9afb3da12b4 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permite setarea pentru alarme și mementouri"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să stabilească alarme și să planifice acțiuni dependente de timp. Astfel, aplicația poate să ruleze în fundal, fapt care ar putea consuma mai multă baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să seteze alarme și să planifice acțiuni care trebuie realizate în timp scurt. Astfel, aplicația poate să ruleze în fundal, ceea ce ar putea crește consumul de baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programare, alarmă, memento, ceas"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activează"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activează Nu deranja"</string> diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml index 1df043538bd9..4772df984ff5 100644 --- a/packages/SettingsLib/res/values-ru/arrays.xml +++ b/packages/SettingsLib/res/values-ru/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Включены фильтры"</item> <item msgid="2779123106632690576">"Включено"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Применен фильтр по заголовкам"</item> - <item msgid="4818549483446395865">"Применен фильтр по медиапакетам A2DP"</item> - <item msgid="8207123990453243311">"Применен фильтр по каналу RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Отключено"</item> - <item msgid="5884245882825346396">"Специальный параметр"</item> - <item msgid="6569400572915342949">"Заголовок"</item> - <item msgid="1239386221416967664">"Общий фильтр"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (по умолчанию)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 76d163cea817..16788c3c828c 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -522,7 +522,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники и напоминания"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разрешить установку будильников и напоминаний"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники и напоминания"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Если вы разрешите этому приложению устанавливать будильники и планировать на определенное время действия, оно будет работать в фоновом режиме. В таком случае заряд батареи может расходоваться быстрее.\n\nЕсли отключить эту настройку, текущие будильники и созданные приложением мероприятия перестанут запускаться."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Вы можете разрешить этому приложению устанавливать будильники и планировать запуск действий в определенное время. В этом случае оно будет работать в фоновом режиме и быстрее расходовать заряд батареи.\n\nЕсли отключить это разрешение, текущие будильники и созданные приложением события перестанут запускаться."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"установить, будильник, напоминание, часы"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Включить"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Включите режим \"Не беспокоить\""</string> diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml index b516ce629980..8de6a71d1dd4 100644 --- a/packages/SettingsLib/res/values-si/arrays.xml +++ b/packages/SettingsLib/res/values-si/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"සබල පෙරහන් කළ"</item> <item msgid="2779123106632690576">"සබලයි"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ශීර්ෂයන් පෙරන ලදි"</item> - <item msgid="4818549483446395865">"A2DP මාධ්ය පැකට් පෙරන ලදි"</item> - <item msgid="8207123990453243311">"RFCOMM නාලිකාව පෙරන ලදි"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"අබලයි"</item> - <item msgid="5884245882825346396">"මැජික්"</item> - <item msgid="6569400572915342949">"ශීර්ෂකය"</item> - <item msgid="1239386221416967664">"පූර්ණ පෙරහන"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (පෙරනිමි)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml index 35c4518c851c..f15dfb7629d3 100644 --- a/packages/SettingsLib/res/values-sk/arrays.xml +++ b/packages/SettingsLib/res/values-sk/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Aktivované filtrované"</item> <item msgid="2779123106632690576">"Aktivované"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Hlavičky sú filtrované"</item> - <item msgid="4818549483446395865">"Balíky A2DP Media sú filtrované"</item> - <item msgid="8207123990453243311">"Kanál RFCOMM je filtrovaný"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Deaktivované"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Hlavička"</item> - <item msgid="1239386221416967664">"Úplný filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (predvolené)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml index 12442a451a57..9ef852c062c2 100644 --- a/packages/SettingsLib/res/values-sl/arrays.xml +++ b/packages/SettingsLib/res/values-sl/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Omogočeno filtrirano"</item> <item msgid="2779123106632690576">"Omogočeno"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Glave so filtrirane"</item> - <item msgid="4818549483446395865">"Predstavnostni paketi A2DP so filtrirani"</item> - <item msgid="8207123990453243311">"Kanal RFCOMM je filtriran"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Onemogočeno"</item> - <item msgid="5884245882825346396">"Čarovnija"</item> - <item msgid="6569400572915342949">"Glava"</item> - <item msgid="1239386221416967664">"Polni filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (privzeto)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml index 742a86a7fbe2..89a316dcd6e7 100644 --- a/packages/SettingsLib/res/values-sq/arrays.xml +++ b/packages/SettingsLib/res/values-sq/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Të aktivizuara të filtruara"</item> <item msgid="2779123106632690576">"Aktiv"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Titujt e filtruar"</item> - <item msgid="4818549483446395865">"Paketat e medias A2DP të filtruara"</item> - <item msgid="8207123990453243311">"Kanalet e RFCOMM të filtruara"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Joaktiv"</item> - <item msgid="5884245882825346396">"Magji"</item> - <item msgid="6569400572915342949">"Titulli"</item> - <item msgid="1239386221416967664">"Filtri i plotë"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (I parazgjedhur)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml index a338142a418e..e76820e3368e 100644 --- a/packages/SettingsLib/res/values-sr/arrays.xml +++ b/packages/SettingsLib/res/values-sr/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Омогућено филтрирано"</item> <item msgid="2779123106632690576">"Омогућено"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Филтрирана заглавља"</item> - <item msgid="4818549483446395865">"Филтрирани A2DP медијски пакети"</item> - <item msgid="8207123990453243311">"Филтрирани RFCOMM канал"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Онемогућено"</item> - <item msgid="5884245882825346396">"Магија"</item> - <item msgid="6569400572915342949">"Заглавље"</item> - <item msgid="1239386221416967664">"Потпуни филтер"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (подразумевано)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml index a31c155f530e..391f603721c2 100644 --- a/packages/SettingsLib/res/values-sv/arrays.xml +++ b/packages/SettingsLib/res/values-sv/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrering har aktiverats"</item> <item msgid="2779123106632690576">"Aktiverad"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Filtrerade rubriker"</item> - <item msgid="4818549483446395865">"Filtrerade A2DP-mediapaket"</item> - <item msgid="8207123990453243311">"Filtrerad RFCOMM-kanal"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Inaktiverad"</item> - <item msgid="5884245882825346396">"Magi"</item> - <item msgid="6569400572915342949">"Rubrik"</item> - <item msgid="1239386221416967664">"Fullständigt filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (standard)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml index 8daf0920d8c5..1a33b6e4ce7c 100644 --- a/packages/SettingsLib/res/values-sw/arrays.xml +++ b/packages/SettingsLib/res/values-sw/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Vichujio Vilivyowekwa"</item> <item msgid="2779123106632690576">"Imewashwa"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Vijajuu Vimechujwa"</item> - <item msgid="4818549483446395865">"Kifurushi cha Maelezo cha A2DP Kimechujwa"</item> - <item msgid="8207123990453243311">"Kituo cha RFCOMM Kimechujwa"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Kimezimwa"</item> - <item msgid="5884245882825346396">"Kiinimacho"</item> - <item msgid="6569400572915342949">"Kijajuu"</item> - <item msgid="1239386221416967664">"Kichujio Kamili"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Chaguomsingi)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml index 8f2fe7e2ab01..23eb2426b49f 100644 --- a/packages/SettingsLib/res/values-ta/arrays.xml +++ b/packages/SettingsLib/res/values-ta/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"இயக்கப்பட்டு வடிகட்டப்பட்டது"</item> <item msgid="2779123106632690576">"இயக்கப்பட்டது"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"வடிகட்டப்பட்ட தலைப்புப்பகுதிகள்"</item> - <item msgid="4818549483446395865">"வடிகட்டப்பட்ட A2DP மீடியா பேக்கெட்டுகள்"</item> - <item msgid="8207123990453243311">"வடிகட்டப்பட்ட RFCOMM சேனல்"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"முடக்கப்பட்டுள்ளது"</item> - <item msgid="5884245882825346396">"மேஜிக்"</item> - <item msgid="6569400572915342949">"தலைப்புப்பகுதி"</item> - <item msgid="1239386221416967664">"முழு வடிப்பான்"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (இயல்பு)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml index 4b07f37a1040..0f62c1d8d842 100644 --- a/packages/SettingsLib/res/values-te/arrays.xml +++ b/packages/SettingsLib/res/values-te/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"ప్రారంభించబడింది ఫిల్టర్ చేయబడింది"</item> <item msgid="2779123106632690576">"ప్రారంభించబడింది"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"హెడర్లు ఫిల్టర్ చేయబడ్డాయి"</item> - <item msgid="4818549483446395865">"A2DP మీడియా ప్యాకెట్లు ఫిల్టర్ చేయబడ్డాయి"</item> - <item msgid="8207123990453243311">"RFCOMM ఛానెల్ ఫిల్టర్ చేయబడింది"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"డిజేబుల్ చేయబడింది"</item> - <item msgid="5884245882825346396">"మ్యాజిక్"</item> - <item msgid="6569400572915342949">"హెడర్"</item> - <item msgid="1239386221416967664">"పూర్తి ఫిల్టర్"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.4 (ఆటోమేటిక్ సెట్టింగ్)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml index be8dd8bb7fdf..8d98cdb54fd3 100644 --- a/packages/SettingsLib/res/values-th/arrays.xml +++ b/packages/SettingsLib/res/values-th/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"เปิดใช้รายการที่กรอง"</item> <item msgid="2779123106632690576">"เปิดใช้"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ส่วนหัวที่กรอง"</item> - <item msgid="4818549483446395865">"แพ็กเก็ตสื่อ A2DP ที่กรอง"</item> - <item msgid="8207123990453243311">"แชแนล RFCOMM ที่กรอง"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"ปิดใช้"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"ส่วนหัว"</item> - <item msgid="1239386221416967664">"ตัวกรองแบบเต็ม"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ค่าเริ่มต้น)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml index 9b4ae0ef8cfd..ed47d3294280 100644 --- a/packages/SettingsLib/res/values-tl/arrays.xml +++ b/packages/SettingsLib/res/values-tl/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Na-enable Na-filter"</item> <item msgid="2779123106632690576">"Naka-enable"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Mga Na-filter na Header"</item> - <item msgid="4818549483446395865">"Mga Na-filter na A2DP Media Packet"</item> - <item msgid="8207123990453243311">"Mga Na-filter na RFCOMM Channel"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Naka-disable"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"Header"</item> - <item msgid="1239386221416967664">"Kumpletong Filter"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml index 57c993514e2e..45580f5b4f2c 100644 --- a/packages/SettingsLib/res/values-tr/arrays.xml +++ b/packages/SettingsLib/res/values-tr/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Etkin Filtrelenmiş"</item> <item msgid="2779123106632690576">"Etkin"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Başlıklar Filtrelendi"</item> - <item msgid="4818549483446395865">"A2DP Medya Paketleri Filtrelendi"</item> - <item msgid="8207123990453243311">"RFCOMM Kanalı Filtrelendi"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Devre dışı"</item> - <item msgid="5884245882825346396">"Sihir"</item> - <item msgid="6569400572915342949">"Başlık"</item> - <item msgid="1239386221416967664">"Tam Filtre"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Varsayılan)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 86d53e7d586d..1f56170f6294 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -520,7 +520,7 @@ <string name="okay" msgid="949938843324579502">"Tamam"</string> <string name="done" msgid="381184316122520313">"Bitti"</string> <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmlar ve hatırlatıcılar"</string> - <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlanmasına izin ver"</string> + <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlamasına izin ver"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmlar ve hatırlatıcılar"</string> <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Bu uygulamanın alarm kurmasına ve zamana bağlı işlemler programlamasına izin verin. Bu izin, uygulamanın arka planda çalışmasına olanak sağlayarak daha fazla pil harcanmasına neden olabilir.\n\nBu izin verilmezse bu uygulama tarafından programlanmış mevcut alarmlar ve zamana bağlı etkinlikler çalışmaz."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"program, alarm, hatırlatıcı, saat"</string> diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml index 53bbb87ef7cf..f97452c159c8 100644 --- a/packages/SettingsLib/res/values-uk/arrays.xml +++ b/packages/SettingsLib/res/values-uk/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Увімкнено з фільтром"</item> <item msgid="2779123106632690576">"Увімкнено"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Фільтрування за заголовками"</item> - <item msgid="4818549483446395865">"Фільтрування за пакетами медіаданих A2DP"</item> - <item msgid="8207123990453243311">"Фільтрування за каналом RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Вимкнено"</item> - <item msgid="5884245882825346396">"Магія"</item> - <item msgid="6569400572915342949">"Заголовок"</item> - <item msgid="1239386221416967664">"Повний фільтр"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (за умовчанням)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml index 5f8206272306..74af32215d1b 100644 --- a/packages/SettingsLib/res/values-ur/arrays.xml +++ b/packages/SettingsLib/res/values-ur/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"فعال کردہ فلٹر کردہ"</item> <item msgid="2779123106632690576">"فعال"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"ہیڈرز فلٹر کئے گئے"</item> - <item msgid="4818549483446395865">"A2DP میڈیا پیکٹ فلٹر کیے گئے"</item> - <item msgid="8207123990453243311">"RFCOMM چینل فلٹر کیا گیا"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"غیر فعال"</item> - <item msgid="5884245882825346396">"جادو"</item> - <item msgid="6569400572915342949">"ہیڈر"</item> - <item msgid="1239386221416967664">"مکمل فلٹر"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (ڈیفالٹ)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml index dc7e6cd539bd..3e53ae6abaf0 100644 --- a/packages/SettingsLib/res/values-uz/arrays.xml +++ b/packages/SettingsLib/res/values-uz/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Filtrlar yoniq"</item> <item msgid="2779123106632690576">"Yoniq"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Sarlavhalar filtrlandi"</item> - <item msgid="4818549483446395865">"A2DP media paketlar filtrlandi"</item> - <item msgid="8207123990453243311">"RFCOMM kanali filtrlandi"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Faolsizlantirilgan"</item> - <item msgid="5884245882825346396">"Sehr"</item> - <item msgid="6569400572915342949">"Sarlavha"</item> - <item msgid="1239386221416967664">"Toʻliq filtrlash"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (asosiy)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml index 18e6c577604d..649cb5cd7693 100644 --- a/packages/SettingsLib/res/values-vi/arrays.xml +++ b/packages/SettingsLib/res/values-vi/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Đã bật và lọc"</item> <item msgid="2779123106632690576">"Đã bật"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Đã lọc tiêu đề"</item> - <item msgid="4818549483446395865">"Đã lọc gói nội dung nghe nhìn A2DP"</item> - <item msgid="8207123990453243311">"Đã lọc kênh RFCOMM"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Đã tắt"</item> - <item msgid="5884245882825346396">"Ảo thuật"</item> - <item msgid="6569400572915342949">"Tiêu đề"</item> - <item msgid="1239386221416967664">"Bộ lọc đầy đủ"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (Mặc định)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml index 0d76e6fd7688..13941af90c8d 100644 --- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"已启用“已过滤”"</item> <item msgid="2779123106632690576">"已启用"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"已过滤标题"</item> - <item msgid="4818549483446395865">"已过滤 A2DP 媒体数据包"</item> - <item msgid="8207123990453243311">"已过滤 RFCOMM 通道"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"已停用"</item> - <item msgid="5884245882825346396">"魔术"</item> - <item msgid="6569400572915342949">"标题"</item> - <item msgid="1239386221416967664">"完整过滤器"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5(默认)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml index c30e9f700427..9b359ed4ea22 100644 --- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"已啟用篩選"</item> <item msgid="2779123106632690576">"已啟用"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"已篩選標題"</item> - <item msgid="4818549483446395865">"已篩選 A2DP 媒體封包"</item> - <item msgid="8207123990453243311">"已篩選 RFCOMM 頻道"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"已停用"</item> - <item msgid="5884245882825346396">"Magic"</item> - <item msgid="6569400572915342949">"標題"</item> - <item msgid="1239386221416967664">"完整篩選器"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (預設)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml index c6073f04b012..00362d828b91 100644 --- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"已啟用篩選結果"</item> <item msgid="2779123106632690576">"已啟用"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"已篩選標頭"</item> - <item msgid="4818549483446395865">"已篩選 A2DP 媒體封包"</item> - <item msgid="8207123990453243311">"已篩選 RFCOMM 管道"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"已停用"</item> - <item msgid="5884245882825346396">"按偏好排序"</item> - <item msgid="6569400572915342949">"標頭"</item> - <item msgid="1239386221416967664">"完整篩選器"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"AVRCP 1.5 (預設)"</item> <item msgid="1637054408779685086">"AVRCP 1.3"</item> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 8bfbd7a5cd00..588c4f4b698e 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -230,7 +230,7 @@ <string name="adb_wireless_error" msgid="721958772149779856">"錯誤"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"無線偵錯"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"如要查看並使用可用的裝置,請開啟無線偵錯功能"</string> - <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR 圖碼配對裝置"</string> + <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR code 配對裝置"</string> <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用 QR code 掃描器配對新裝置"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配對碼配對裝置"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位數的配對碼配對新裝置"</string> diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml index 8b23bbbbe117..ac3cb024fef8 100644 --- a/packages/SettingsLib/res/values-zu/arrays.xml +++ b/packages/SettingsLib/res/values-zu/arrays.xml @@ -63,17 +63,13 @@ <item msgid="6336372935919715515">"Okuhlungiwe okunikwe amandla"</item> <item msgid="2779123106632690576">"Kunikwe amandla"</item> </string-array> - <string-array name="bt_hci_snoop_log_filters_entries"> - <item msgid="5118179698172834473">"Izihloko Zihlungiwe"</item> - <item msgid="4818549483446395865">"I-A2DP Media Packets Ihlungiwe"</item> - <item msgid="8207123990453243311">"Isiteshi se-RFCOMM Sihlungiwe"</item> - </string-array> - <string-array name="bt_hci_snoop_log_profile_filter_entries"> - <item msgid="6348114316510677939">"Kukhutshaziwe"</item> - <item msgid="5884245882825346396">"Umlingo"</item> - <item msgid="6569400572915342949">"Unhlokweni"</item> - <item msgid="1239386221416967664">"Isihlungi Esigcwele"</item> - </string-array> + <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (195768089203590086) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (2776218217644557831) --> + <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8163235976612675092) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (3961868665260627524) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (2505973306504851132) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (5883011000629613855) --> + <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1051534112762023603) --> <string-array name="bluetooth_avrcp_versions"> <item msgid="6603880723315236832">"I-AVRCP 1.5 (Okuzenzakalelayo)"</item> <item msgid="1637054408779685086">"I-AVRCP 1.3"</item> diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java index 28353ab7dff4..52f3111d967c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java @@ -169,8 +169,11 @@ public class BatterySaverUtils { */ public static boolean maybeShowBatterySaverConfirmation(Context context, Bundle extras) { if (Secure.getInt(context.getContentResolver(), - Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) { - return false; // Already shown. + Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0 + && Secure.getInt(context.getContentResolver(), + Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) { + // Already shown. + return false; } context.sendBroadcast( getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, extras)); @@ -190,8 +193,10 @@ public class BatterySaverUtils { } private static void setBatterySaverConfirmationAcknowledged(Context context) { - Secure.putIntForUser(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1, - UserHandle.USER_CURRENT); + Secure.putIntForUser(context.getContentResolver(), + Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT); + Secure.putIntForUser(context.getContentResolver(), + Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT); } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java b/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java index dc8a862d72c7..31f014c27a13 100644 --- a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java @@ -62,16 +62,7 @@ public class UdfpsUtils { */ public Point getTouchInNativeCoordinates(int idx, MotionEvent event, UdfpsOverlayParams udfpsOverlayParams) { - Point portraitTouch = new Point((int) event.getRawX(idx), (int) event.getRawY(idx)); - int rot = udfpsOverlayParams.getRotation(); - if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { - RotationUtils.rotatePoint( - portraitTouch, - RotationUtils.deltaRotation(rot, Surface.ROTATION_0), - udfpsOverlayParams.getLogicalDisplayWidth(), - udfpsOverlayParams.getLogicalDisplayHeight() - ); - } + Point portraitTouch = getPortraitTouch(idx, event, udfpsOverlayParams); // Scale the coordinates to native resolution. float scale = udfpsOverlayParams.getScaleFactor(); @@ -81,13 +72,25 @@ public class UdfpsUtils { } /** + * @param idx The pointer identifier. + * @param event The MotionEvent object containing full information about the event. + * @param udfpsOverlayParams The [UdfpsOverlayParams] used. + * @return Whether the touch event is within sensor area. + */ + public boolean isWithinSensorArea(int idx, MotionEvent event, + UdfpsOverlayParams udfpsOverlayParams) { + Point portraitTouch = getPortraitTouch(idx, event, udfpsOverlayParams); + return udfpsOverlayParams.getSensorBounds().contains(portraitTouch.x, portraitTouch.y); + } + + /** * This function computes the angle of touch relative to the sensor and maps the angle to a list * of help messages which are announced if accessibility is enabled. * * @return Whether the announcing string is null */ - public String onTouchOutsideOfSensorArea(boolean touchExplorationEnabled, - Context context, int touchX, int touchY, UdfpsOverlayParams udfpsOverlayParams) { + public String onTouchOutsideOfSensorArea(boolean touchExplorationEnabled, Context context, + int scaledTouchX, int scaledTouchY, UdfpsOverlayParams udfpsOverlayParams) { if (!touchExplorationEnabled) { return null; } @@ -106,8 +109,8 @@ public class UdfpsUtils { String theStr = onTouchOutsideOfSensorAreaImpl( touchHints, - touchX, - touchY, + scaledTouchX, + scaledTouchY, scaledSensorX, scaledSensorY, udfpsOverlayParams.getRotation() @@ -156,4 +159,22 @@ public class UdfpsUtils { } return touchHints[index]; } + + /** + * Map the touch to portrait mode if the device is in landscape mode. + */ + private Point getPortraitTouch(int idx, MotionEvent event, + UdfpsOverlayParams udfpsOverlayParams) { + Point portraitTouch = new Point((int) event.getRawX(idx), (int) event.getRawY(idx)); + int rot = udfpsOverlayParams.getRotation(); + if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { + RotationUtils.rotatePoint( + portraitTouch, + RotationUtils.deltaRotation(rot, Surface.ROTATION_0), + udfpsOverlayParams.getLogicalDisplayWidth(), + udfpsOverlayParams.getLogicalDisplayHeight() + ); + } + return portraitTouch; + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java index a15fe9f90206..ad022a63eaf6 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java @@ -69,6 +69,7 @@ public class BatterySaverUtilsTest { @Test public void testSetPowerSaveMode_enable_firstCall_needWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); + Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isFalse(); @@ -77,15 +78,18 @@ public class BatterySaverUtilsTest { verify(mMockPowerManager, times(0)).setPowerSaveModeEnabled(anyBoolean()); // They shouldn't have changed. + assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); assertEquals(-1, - Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); + Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1)); assertEquals(-2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); } @Test public void testSetPowerSaveMode_enable_secondCall_needWarning() { - Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked. + // Already acked. + Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); + Secure.putInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue(); @@ -94,12 +98,17 @@ public class BatterySaverUtilsTest { verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true)); assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); - assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); + assertEquals(1, + Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1)); + assertEquals(1, + Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); } @Test public void testSetPowerSaveMode_enable_thridCall_needWarning() { - Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked. + // Already acked. + Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); + Secure.putInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1); Secure.putInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 1); assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue(); @@ -108,12 +117,16 @@ public class BatterySaverUtilsTest { verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true)); assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); - assertEquals(2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); + assertEquals(1, + Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1)); + assertEquals(2, + Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); } @Test public void testSetPowerSaveMode_enable_firstCall_noWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); + Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, false)).isTrue(); @@ -122,12 +135,15 @@ public class BatterySaverUtilsTest { verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true)); assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); + assertEquals(1, + Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1)); assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); } @Test public void testSetPowerSaveMode_disable_firstCall_noWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); + Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); // When disabling, needFirstTimeWarning doesn't matter. @@ -137,6 +153,8 @@ public class BatterySaverUtilsTest { verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false)); assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); + assertEquals(-1, + Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1)); assertEquals(-2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); } @@ -144,6 +162,7 @@ public class BatterySaverUtilsTest { @Test public void testSetPowerSaveMode_disable_firstCall_needWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); + Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); // When disabling, needFirstTimeWarning doesn't matter. @@ -153,6 +172,8 @@ public class BatterySaverUtilsTest { verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false)); assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1)); + assertEquals(-1, + Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1)); assertEquals(-2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2)); } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 93394f3872ee..f66fcba74bc5 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -239,5 +239,6 @@ public class SecureSettings { Settings.Secure.HEARING_AID_CALL_ROUTING, Settings.Secure.HEARING_AID_MEDIA_ROUTING, Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, + Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index c9d840a77b80..6a5535d345db 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -97,5 +97,8 @@ public class SystemSettings { Settings.System.TOUCHPAD_NATURAL_SCROLLING, Settings.System.TOUCHPAD_TAP_TO_CLICK, Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, + Settings.System.CAMERA_FLASH_NOTIFICATION, + Settings.System.SCREEN_FLASH_NOTIFICATION, + Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 96578626d5cc..558e19f19986 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -376,5 +376,6 @@ public class SecureSettingsValidators { new DiscreteValueValidator(new String[] {"0", "1", "2"})); VALIDATORS.put(Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, new DiscreteValueValidator(new String[] {"0", "1", "2"})); + VALIDATORS.put(Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, BOOLEAN_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index c2a3ada53591..3fe12b3dab32 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -16,6 +16,7 @@ package android.provider.settings.validators; +import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR; @@ -215,5 +216,8 @@ public class SystemSettingsValidators { VALIDATORS.put(System.UNREAD_NOTIFICATION_DOT_INDICATOR, BOOLEAN_VALIDATOR); VALIDATORS.put(System.AUTO_LAUNCH_MEDIA_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(System.LOCALE_PREFERENCES, ANY_STRING_VALIDATOR); + VALIDATORS.put(System.CAMERA_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR); + VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR); + VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION_COLOR, ANY_INTEGER_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java index 7f3b0ff8c838..db6cc1a39ef1 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java @@ -16,6 +16,7 @@ package com.android.providers.settings; +import android.annotation.NonNull; import android.os.Bundle; import android.provider.Settings; import android.util.ArrayMap; @@ -59,6 +60,10 @@ final class GenerationRegistry { // Maximum size of an individual backing store static final int MAX_BACKING_STORE_SIZE = MemoryIntArray.getMaxSize(); + // Use an empty string to track the generation number of all non-predefined, unset settings + // The generation number is only increased when a new non-predefined setting is inserted + private static final String DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS = ""; + public GenerationRegistry(Object lock) { mLock = lock; } @@ -72,6 +77,10 @@ final class GenerationRegistry { (SettingsState.getTypeFromKey(key) == SettingsState.SETTINGS_TYPE_CONFIG); // Only store the prefix if the mutated setting is a config final String indexMapKey = isConfig ? (name.split("/")[0] + "/") : name; + incrementGenerationInternal(key, indexMapKey); + } + + private void incrementGenerationInternal(int key, @NonNull String indexMapKey) { synchronized (mLock) { final MemoryIntArray backingStore = getBackingStoreLocked(key, /* createIfNotExist= */ false); @@ -87,7 +96,8 @@ final class GenerationRegistry { final int generation = backingStore.get(index) + 1; backingStore.set(index, generation); if (DEBUG) { - Slog.i(LOG_TAG, "Incremented generation for setting:" + indexMapKey + Slog.i(LOG_TAG, "Incremented generation for " + + (indexMapKey.isEmpty() ? "unset settings" : "setting:" + indexMapKey) + " key:" + SettingsState.keyToString(key) + " at index:" + index); } @@ -98,6 +108,18 @@ final class GenerationRegistry { } } + // A new, non-predefined setting has been inserted, increment the tracking number for all unset + // settings + public void incrementGenerationForUnsetSettings(int key) { + final boolean isConfig = + (SettingsState.getTypeFromKey(key) == SettingsState.SETTINGS_TYPE_CONFIG); + if (isConfig) { + // No need to track new settings for configs + return; + } + incrementGenerationInternal(key, DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS); + } + /** * Return the backing store's reference, the index and the current generation number * of a cached setting. If it was not in the backing store, first create the entry in it before @@ -124,8 +146,8 @@ final class GenerationRegistry { bundle.putInt(Settings.CALL_METHOD_GENERATION_KEY, backingStore.get(index)); if (DEBUG) { - Slog.i(LOG_TAG, "Exported index:" + index - + " for setting:" + indexMapKey + Slog.i(LOG_TAG, "Exported index:" + index + " for " + + (indexMapKey.isEmpty() ? "unset settings" : "setting:" + indexMapKey) + " key:" + SettingsState.keyToString(key)); } } catch (IOException e) { @@ -135,6 +157,10 @@ final class GenerationRegistry { } } + public void addGenerationDataForUnsetSettings(Bundle bundle, int key) { + addGenerationData(bundle, key, /* indexMapKey= */ DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS); + } + public void onUserRemoved(int userId) { final int secureKey = SettingsState.makeKey( SettingsState.SETTINGS_TYPE_SECURE, userId); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index fb3c3136280e..d49627e5334a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1852,6 +1852,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, SecureSettingsProto.Accessibility.HEARING_AID_SYSTEM_SOUNDS_ROUTING); + dumpSetting(s, p, + Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, + SecureSettingsProto.Accessibility.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED); p.end(accessibilityToken); final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP); @@ -2832,6 +2835,15 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.System.NOTIFICATION_VIBRATION_INTENSITY, SystemSettingsProto.Notification.VIBRATION_INTENSITY); + dumpSetting(s, p, + Settings.System.CAMERA_FLASH_NOTIFICATION, + SystemSettingsProto.Notification.CAMERA_FLASH_NOTIFICATION); + dumpSetting(s, p, + Settings.System.SCREEN_FLASH_NOTIFICATION, + SystemSettingsProto.Notification.SCREEN_FLASH_NOTIFICATION); + dumpSetting(s, p, + Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, + SystemSettingsProto.Notification.SCREEN_FLASH_NOTIFICATION_COLOR_GLOBAL); // Settings.System.NOTIFICATIONS_USE_RING_VOLUME intentionally excluded since it's deprecated. p.end(notificationToken); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index ba275ebca168..418011acf6f3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2327,11 +2327,15 @@ public class SettingsProvider extends ContentProvider { result.putString(Settings.NameValueTable.VALUE, (setting != null && !setting.isNull()) ? setting.getValue() : null); - if ((setting != null && !setting.isNull()) || isSettingPreDefined(name, type)) { - // Don't track generation for non-existent settings unless the name is predefined - synchronized (mLock) { + synchronized (mLock) { + if ((setting != null && !setting.isNull()) || isSettingPreDefined(name, type)) { + // Individual generation tracking for predefined settings even if they are unset mSettingsRegistry.mGenerationRegistry.addGenerationData(result, SettingsState.makeKey(type, userId), name); + } else { + // All non-predefined, unset settings are tracked using the same generation number + mSettingsRegistry.mGenerationRegistry.addGenerationDataForUnsetSettings(result, + SettingsState.makeKey(type, userId)); } } return result; @@ -2345,7 +2349,8 @@ public class SettingsProvider extends ContentProvider { } else if (type == SETTINGS_TYPE_SYSTEM) { return sAllSystemSettings.contains(name); } else { - return false; + // Consider all config settings predefined because they are used by system apps only + return type == SETTINGS_TYPE_CONFIG; } } @@ -2354,14 +2359,13 @@ public class SettingsProvider extends ContentProvider { Bundle result = new Bundle(); result.putSerializable(Settings.NameValueTable.VALUE, keyValues); if (trackingGeneration) { - // Track generation even if the namespace is empty because this is for system apps synchronized (mLock) { + // Track generation even if namespace is empty because this is for system apps only mSettingsRegistry.mGenerationRegistry.addGenerationData(result, - mSettingsRegistry.getSettingsLocked(SETTINGS_TYPE_CONFIG, - UserHandle.USER_SYSTEM).mKey, prefix); + SettingsState.makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM), + prefix); } } - return result; } @@ -3052,10 +3056,15 @@ public class SettingsProvider extends ContentProvider { final int key = makeKey(type, userId); boolean success = false; + boolean isNewSetting = false; SettingsState settingsState = peekSettingsStateLocked(key); if (settingsState != null) { + if (!settingsState.hasSetting(name)) { + isNewSetting = true; + } success = settingsState.insertSettingLocked(name, value, - tag, makeDefault, forceNonSystemPackage, packageName, overrideableByRestore); + tag, makeDefault, forceNonSystemPackage, packageName, + overrideableByRestore); } if (success && criticalSettings != null && criticalSettings.contains(name)) { @@ -3064,6 +3073,11 @@ public class SettingsProvider extends ContentProvider { if (forceNotify || success) { notifyForSettingsChange(key, name); + if (isNewSetting && !isSettingPreDefined(name, type)) { + // Increment the generation number for all null settings because a new + // non-predefined setting has been inserted + mGenerationRegistry.incrementGenerationForUnsetSettings(key); + } } if (success) { logSettingChanged(userId, name, type, CHANGE_TYPE_INSERT); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index c3888268a61d..4d8705f135af 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -759,6 +759,12 @@ final class SettingsState { mPackageToMemoryUsage.put(packageName, newSize); } + public boolean hasSetting(String name) { + synchronized (mLock) { + return hasSettingLocked(name); + } + } + @GuardedBy("mLock") private boolean hasSettingLocked(String name) { return mSettings.indexOfKey(name) >= 0; diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java index d34fe6943153..6ec8146baee0 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java @@ -151,6 +151,26 @@ public class GenerationRegistryTest { checkBundle(b, 0, 1, false); } + @Test + public void testUnsetSettings() throws IOException { + final GenerationRegistry generationRegistry = new GenerationRegistry(new Object()); + final int secureKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_SECURE, 0); + final String testSecureSetting = "test_secure_setting"; + Bundle b = new Bundle(); + generationRegistry.addGenerationData(b, secureKey, testSecureSetting); + checkBundle(b, 0, 1, false); + generationRegistry.addGenerationDataForUnsetSettings(b, secureKey); + checkBundle(b, 1, 1, false); + generationRegistry.addGenerationDataForUnsetSettings(b, secureKey); + // Test that unset settings always have the same index + checkBundle(b, 1, 1, false); + generationRegistry.incrementGenerationForUnsetSettings(secureKey); + // Test that the generation number of the unset settings have increased + generationRegistry.addGenerationDataForUnsetSettings(b, secureKey); + checkBundle(b, 1, 2, false); + } + + private void checkBundle(Bundle b, int expectedIndex, int expectedGeneration, boolean isNull) throws IOException { final MemoryIntArray array = getArray(b); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 90bec4292313..d02e5693bbf3 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -721,6 +721,7 @@ <!-- Permission required for CTS test - CtsTelephonyTestCases --> <uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" /> <uses-permission android:name="android.permission.MODIFY_CELL_BROADCASTS" /> + <uses-permission android:name="android.permission.SATELLITE_COMMUNICATION" /> <!-- Permission required for CTS test - CtsPersistentDataBlockManagerTestCases --> <uses-permission android:name="android.permission.ACCESS_PDB_STATE" /> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 4e18222355e6..71f438eb0455 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -341,6 +341,8 @@ <uses-permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" /> + <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" /> + <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/Android.bp index 140c10da922e..f358417e6bea 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/Android.bp +++ b/packages/SystemUI/accessibility/accessibilitymenu/Android.bp @@ -18,6 +18,15 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +// This filegroup is used by menu tests. +filegroup { + name: "AccessibilityMenuSource", + srcs: [ + "src/**/AccessibilityMenuService.java", + "src/**/A11yMenuShortcut.java", + ], +} + android_app { name: "AccessibilityMenu", diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml index 39e5a8c6876b..a902c5b54b7b 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/shortcutItem" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingTop="@dimen/grid_item_padding" diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java index c1f2aa86c6b5..8ca64d2505ce 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.accessibilitymenu; +import android.Manifest; import android.accessibilityservice.AccessibilityButtonController; import android.accessibilityservice.AccessibilityService; import android.content.BroadcastReceiver; @@ -51,8 +52,12 @@ import java.util.List; /** @hide */ public class AccessibilityMenuService extends AccessibilityService implements View.OnTouchListener { - private static final String TAG = "A11yMenuService"; + public static final String PACKAGE_NAME = AccessibilityMenuService.class.getPackageName(); + public static final String INTENT_TOGGLE_MENU = ".toggle_menu"; + public static final String INTENT_HIDE_MENU = ".hide_menu"; + + private static final String TAG = "A11yMenuService"; private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L; private static final int BRIGHTNESS_UP_INCREMENT_GAMMA = @@ -74,7 +79,8 @@ public class AccessibilityMenuService extends AccessibilityService // TODO(b/136716947): Support multi-display once a11y framework side is ready. private DisplayManager mDisplayManager; - final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { + private final DisplayManager.DisplayListener mDisplayListener = + new DisplayManager.DisplayListener() { int mRotation; @Override @@ -95,13 +101,20 @@ public class AccessibilityMenuService extends AccessibilityService } }; - final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mHideMenuReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mA11yMenuLayout.hideMenu(); } }; + private final BroadcastReceiver mToggleMenuReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mA11yMenuLayout.toggleVisibility(); + } + }; + /** * Update a11y menu layout when large button setting is changed. */ @@ -172,7 +185,19 @@ public class AccessibilityMenuService extends AccessibilityService protected void onServiceConnected() { mA11yMenuLayout = new A11yMenuOverlayLayout(this); - registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); + IntentFilter hideMenuFilter = new IntentFilter(); + hideMenuFilter.addAction(Intent.ACTION_SCREEN_OFF); + hideMenuFilter.addAction(PACKAGE_NAME + INTENT_HIDE_MENU); + + // Including WRITE_SECURE_SETTINGS enforces that we only listen to apps + // with the restricted WRITE_SECURE_SETTINGS permission who broadcast this intent. + registerReceiver(mHideMenuReceiver, hideMenuFilter, + Manifest.permission.WRITE_SECURE_SETTINGS, null, + Context.RECEIVER_EXPORTED); + registerReceiver(mToggleMenuReceiver, + new IntentFilter(PACKAGE_NAME + INTENT_TOGGLE_MENU), + Manifest.permission.WRITE_SECURE_SETTINGS, null, + Context.RECEIVER_EXPORTED); mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mPrefs.registerOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener); @@ -260,7 +285,8 @@ public class AccessibilityMenuService extends AccessibilityService * @param increment The increment amount in gamma-space */ private void adjustBrightness(int increment) { - BrightnessInfo info = getDisplay().getBrightnessInfo(); + Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); + BrightnessInfo info = display.getBrightnessInfo(); int gamma = BrightnessUtils.convertLinearToGammaFloat( info.brightness, info.brightnessMinimum, @@ -275,7 +301,7 @@ public class AccessibilityMenuService extends AccessibilityService info.brightnessMinimum, info.brightnessMaximum ); - mDisplayManager.setBrightness(getDisplayId(), brightness); + mDisplayManager.setBrightness(display.getDisplayId(), brightness); mA11yMenuLayout.showSnackbar( getString(R.string.brightness_percentage_label, (gamma / (BrightnessUtils.GAMMA_SPACE_MAX / 100)))); @@ -310,7 +336,8 @@ public class AccessibilityMenuService extends AccessibilityService @Override public boolean onUnbind(Intent intent) { - unregisterReceiver(mBroadcastReceiver); + unregisterReceiver(mHideMenuReceiver); + unregisterReceiver(mToggleMenuReceiver); mPrefs.unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener); sInitialized = false; return super.onUnbind(intent); diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java index 6f0fe374d6f6..6ae65cb6d8f6 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java @@ -21,6 +21,7 @@ import android.view.LayoutInflater; import android.view.TouchDelegate; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.BaseAdapter; import android.widget.ImageButton; import android.widget.TextView; @@ -146,6 +147,15 @@ public class A11yMenuAdapter extends BaseAdapter { shortcutIconButton.setBackground( mShortcutDrawableUtils.createAdaptiveIconDrawable(shortcutItem.imageColor)); + + shortcutIconButton.setAccessibilityDelegate(new View.AccessibilityDelegate() { + @Override + public void onInitializeAccessibilityNodeInfo( + View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setUniqueId(host.getTag().toString()); + } + }); } } } diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp new file mode 100644 index 000000000000..1757dda84eef --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp @@ -0,0 +1,43 @@ +// +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test { + name: "AccessibilityMenuServiceTests", + certificate: "platform", + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.runner", + "androidx.test.ext.junit", + "compatibility-device-util-axt", + "platform-test-annotations", + "truth-prebuilt", + ], + srcs: [ + "src/**/*.java", + ":AccessibilityMenuSource", + ], + platform_apis: true, + test_suites: ["device-tests"], + instrumentation_for: "AccessibilityMenu", +} diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml b/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml new file mode 100644 index 000000000000..7be6ca742376 --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.systemui.accessibility.accessibilitymenu.tests"> + + <!-- Needed to write to Settings.Secure to enable and disable the service under test. --> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/> + + <application android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.systemui.accessibility.accessibilitymenu.tests" + android:label="AccessibilityMenu Test Cases"> + </instrumentation> +</manifest>
\ No newline at end of file diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidTest.xml b/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidTest.xml new file mode 100644 index 000000000000..39bee5392720 --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidTest.xml @@ -0,0 +1,29 @@ +<?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. +--> +<configuration description="Runs AccessibilityMenu Test Cases."> + <option name="test-tag" value="AccessibilityMenuServiceTests" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="AccessibilityMenuServiceTests.apk" /> + <option name="aapt-version" value="AAPT2" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.systemui.accessibility.accessibilitymenu.tests" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + </test> +</configuration>
\ No newline at end of file diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/TEST_MAPPING b/packages/SystemUI/accessibility/accessibilitymenu/tests/TEST_MAPPING new file mode 100644 index 000000000000..2bd52b552698 --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/TEST_MAPPING @@ -0,0 +1,15 @@ +{ + "presubmit": [ + { + "name": "AccessibilityMenuServiceTests", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "android.support.test.filters.FlakyTest" + } + ] + } + ] +}
\ No newline at end of file diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java new file mode 100644 index 000000000000..529a70c1ab18 --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.accessibilitymenu.tests; + +import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_HIDE_MENU; +import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_TOGGLE_MENU; +import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.PACKAGE_NAME; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.app.Instrumentation; +import android.app.UiAutomation; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.BrightnessInfo; +import android.hardware.display.DisplayManager; +import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.compatibility.common.util.TestUtils; +import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut.ShortcutId; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class AccessibilityMenuServiceTest { + private static final String TAG = "A11yMenuServiceTest"; + + private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5; + private static final int TIMEOUT_UI_CHANGE_S = 5; + + private static Instrumentation sInstrumentation; + private static UiAutomation sUiAutomation; + + private static AccessibilityManager sAccessibilityManager; + + @BeforeClass + public static void classSetup() throws Throwable { + final String serviceName = PACKAGE_NAME + "/.AccessibilityMenuService"; + sInstrumentation = InstrumentationRegistry.getInstrumentation(); + sUiAutomation = sInstrumentation.getUiAutomation( + UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); + final Context context = sInstrumentation.getContext(); + sAccessibilityManager = context.getSystemService(AccessibilityManager.class); + + // Disable all a11yServices if any are active. + if (!sAccessibilityManager.getEnabledAccessibilityServiceList( + AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) { + Settings.Secure.putString(context.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ""); + TestUtils.waitUntil("Failed to disable all services", + TIMEOUT_SERVICE_STATUS_CHANGE_S, + () -> sAccessibilityManager.getEnabledAccessibilityServiceList( + AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()); + } + + // Enable a11yMenu service. + Settings.Secure.putString(context.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, serviceName); + + TestUtils.waitUntil("Failed to enable service", + TIMEOUT_SERVICE_STATUS_CHANGE_S, + () -> sAccessibilityManager.getEnabledAccessibilityServiceList( + AccessibilityServiceInfo.FEEDBACK_ALL_MASK).stream().filter( + info -> info.getId().contains(serviceName)).count() == 1); + } + + @AfterClass + public static void classTeardown() throws Throwable { + Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ""); + } + + private boolean isMenuVisible() { + return sUiAutomation.getRootInActiveWindow() != null + && sUiAutomation.getRootInActiveWindow().getPackageName().toString().equals( + PACKAGE_NAME); + } + + private void openMenu() throws Throwable { + if (isMenuVisible()) { + return; + } + Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU); + sInstrumentation.getContext().sendBroadcast(intent); + TestUtils.waitUntil("Timed out before menu could appear.", + TIMEOUT_UI_CHANGE_S, () -> isMenuVisible()); + } + + private void closeMenu() throws Throwable { + if (!isMenuVisible()) { + return; + } + Intent intent = new Intent(PACKAGE_NAME + INTENT_HIDE_MENU); + sInstrumentation.getContext().sendBroadcast(intent); + TestUtils.waitUntil("Timed out before menu could close.", + TIMEOUT_UI_CHANGE_S, () -> !isMenuVisible()); + } + + private List<AccessibilityNodeInfo> getGridButtonList() { + return sUiAutomation.getRootInActiveWindow() + .findAccessibilityNodeInfosByViewId(PACKAGE_NAME + ":id/shortcutIconBtn"); + } + + private AccessibilityNodeInfo findGridButtonInfo( + List<AccessibilityNodeInfo> buttons, String text) { + for (AccessibilityNodeInfo button: buttons) { + if (button.getUniqueId().equals(text)) { + return button; + } + } + return null; + } + + @Test + public void testAdjustBrightness() throws Throwable { + openMenu(); + + Context context = sInstrumentation.getTargetContext(); + DisplayManager displayManager = context.getSystemService( + DisplayManager.class); + float resetBrightness = displayManager.getBrightness(context.getDisplayId()); + + List<AccessibilityNodeInfo> buttons = getGridButtonList(); + AccessibilityNodeInfo brightnessUpButton = findGridButtonInfo(buttons, + String.valueOf(ShortcutId.ID_BRIGHTNESS_UP_VALUE.ordinal())); + AccessibilityNodeInfo brightnessDownButton = findGridButtonInfo(buttons, + String.valueOf(ShortcutId.ID_BRIGHTNESS_DOWN_VALUE.ordinal())); + + int clickId = AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.getId(); + BrightnessInfo brightnessInfo = displayManager.getDisplay( + context.getDisplayId()).getBrightnessInfo(); + + try { + displayManager.setBrightness(context.getDisplayId(), brightnessInfo.brightnessMinimum); + TestUtils.waitUntil("Could not change to minimum brightness", + TIMEOUT_UI_CHANGE_S, + () -> displayManager.getBrightness(context.getDisplayId()) + == brightnessInfo.brightnessMinimum); + brightnessUpButton.performAction(clickId); + TestUtils.waitUntil("Did not detect an increase in brightness.", + TIMEOUT_UI_CHANGE_S, + () -> displayManager.getBrightness(context.getDisplayId()) + > brightnessInfo.brightnessMinimum); + + displayManager.setBrightness(context.getDisplayId(), brightnessInfo.brightnessMaximum); + TestUtils.waitUntil("Could not change to maximum brightness", + TIMEOUT_UI_CHANGE_S, + () -> displayManager.getBrightness(context.getDisplayId()) + == brightnessInfo.brightnessMaximum); + brightnessDownButton.performAction(clickId); + TestUtils.waitUntil("Did not detect a decrease in brightness.", + TIMEOUT_UI_CHANGE_S, + () -> displayManager.getBrightness(context.getDisplayId()) + < brightnessInfo.brightnessMaximum); + } finally { + displayManager.setBrightness(context.getDisplayId(), resetBrightness); + closeMenu(); + } + } +} diff --git a/packages/SystemUI/animation/.gitignore b/packages/SystemUI/animation/.gitignore new file mode 100644 index 000000000000..f9a33dbbcc7e --- /dev/null +++ b/packages/SystemUI/animation/.gitignore @@ -0,0 +1,9 @@ +.idea/ +.gradle/ +gradle/ +build/ +gradlew* +local.properties +*.iml +android.properties +buildSrc
\ No newline at end of file diff --git a/packages/SystemUI/animation/build.gradle b/packages/SystemUI/animation/build.gradle new file mode 100644 index 000000000000..939455fa44ac --- /dev/null +++ b/packages/SystemUI/animation/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +// TODO: Pull out surfaceeffects outside of src and have separate build files there. +android { + sourceSets { + main { + java.srcDirs = ["${SYS_UI_DIR}/animation/src/com/android/systemui/surfaceeffects/"] + manifest.srcFile "${SYS_UI_DIR}/animation/AndroidManifest.xml" + } + } + + compileSdk 33 + + defaultConfig { + minSdk 33 + targetSdk 33 + } + + lintOptions { + abortOnError false + } + tasks.lint.enabled = false + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" + } + kotlinOptions { + jvmTarget = '1.8' + freeCompilerArgs = ["-Xjvm-default=all"] + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0" + implementation 'androidx.core:core-animation:1.0.0-alpha02' + implementation 'androidx.core:core-ktx:1.9.0' +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt new file mode 100644 index 000000000000..35dbb89ad801 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt @@ -0,0 +1,80 @@ +/* + * 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.util + +import androidx.core.animation.Animator + +/** + * Add an action which will be invoked when the animation has ended. + * + * @return the [Animator.AnimatorListener] added to the Animator + * @see Animator.end + */ +inline fun Animator.doOnEnd( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onEnd = action) + +/** + * Add an action which will be invoked when the animation has started. + * + * @return the [Animator.AnimatorListener] added to the Animator + * @see Animator.start + */ +inline fun Animator.doOnStart( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onStart = action) + +/** + * Add an action which will be invoked when the animation has been cancelled. + * + * @return the [Animator.AnimatorListener] added to the Animator + * @see Animator.cancel + */ +inline fun Animator.doOnCancel( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onCancel = action) + +/** + * Add an action which will be invoked when the animation has repeated. + * + * @return the [Animator.AnimatorListener] added to the Animator + */ +inline fun Animator.doOnRepeat( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onRepeat = action) + +/** + * Add a listener to this Animator using the provided actions. + * + * @return the [Animator.AnimatorListener] added to the Animator + */ +inline fun Animator.addListener( + crossinline onEnd: (animator: Animator) -> Unit = {}, + crossinline onStart: (animator: Animator) -> Unit = {}, + crossinline onCancel: (animator: Animator) -> Unit = {}, + crossinline onRepeat: (animator: Animator) -> Unit = {} +): Animator.AnimatorListener { + val listener = + object : Animator.AnimatorListener { + override fun onAnimationRepeat(animator: Animator) = onRepeat(animator) + override fun onAnimationEnd(animator: Animator) = onEnd(animator) + override fun onAnimationCancel(animator: Animator) = onCancel(animator) + override fun onAnimationStart(animator: Animator) = onStart(animator) + } + addListener(listener) + return listener +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt new file mode 100644 index 000000000000..f64ea4561906 --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.client.api.UElementHandler +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UElement + +class DemotingTestWithoutBugDetector : Detector(), SourceCodeScanner { + override fun getApplicableUastTypes(): List<Class<out UElement>> { + return listOf(UAnnotation::class.java) + } + + override fun createUastHandler(context: JavaContext): UElementHandler { + return object : UElementHandler() { + override fun visitAnnotation(node: UAnnotation) { + if (node.qualifiedName !in DEMOTING_ANNOTATION) { + return + } + val bugId = node.findAttributeValue("bugId")!!.evaluate() as Int + if (bugId <= 0) { + val location = context.getLocation(node) + val message = "Please attach a bug id to track demoted test" + context.report(ISSUE, node, location, message) + } + } + } + } + + companion object { + val DEMOTING_ANNOTATION = + listOf("androidx.test.filters.FlakyTest", "android.platform.test.annotations.FlakyTest") + + @JvmField + val ISSUE: Issue = + Issue.create( + id = "DemotingTestWithoutBug", + briefDescription = "Demoting a test without attaching a bug.", + explanation = + """ + Annotations (`@FlakyTest`) demote tests to an unmonitored \ + test suite. Please set the `bugId` field in such annotations to track \ + the test status. + """, + category = Category.TESTING, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + DemotingTestWithoutBugDetector::class.java, + Scope.JAVA_FILE_SCOPE + ) + ) + } +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt index 84f70502fa45..387b67d231cd 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt @@ -39,7 +39,8 @@ class SystemUIIssueRegistry : IssueRegistry() { RegisterReceiverViaContextDetector.ISSUE, SoftwareBitmapDetector.ISSUE, NonInjectedServiceDetector.ISSUE, - StaticSettingsProviderDetector.ISSUE + StaticSettingsProviderDetector.ISSUE, + DemotingTestWithoutBugDetector.ISSUE ) override val api: Int diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt new file mode 100644 index 000000000000..557c300635eb --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestFiles +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class DemotingTestWithoutBugDetectorTest : SystemUILintDetectorTest() { + + override fun getDetector(): Detector = DemotingTestWithoutBugDetector() + override fun getIssues(): List<Issue> = listOf(DemotingTestWithoutBugDetector.ISSUE) + + @Test + fun testMarkFlaky_withBugId() { + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import androidx.test.filters.FlakyTest; + + @FlakyTest(bugId = 123) + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expectClean() + + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import android.platform.test.annotations.FlakyTest; + + @FlakyTest(bugId = 123) + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expectClean() + } + + @Test + fun testMarkFlaky_withoutBugId() { + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import androidx.test.filters.FlakyTest; + + @FlakyTest + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expect( + """ + src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug] + @FlakyTest + ~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import android.platform.test.annotations.FlakyTest; + + @FlakyTest + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expect( + """ + src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug] + @FlakyTest + ~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + } + + private val filtersFlakyTestStub: TestFile = + java( + """ + package androidx.test.filters; + + public @interface FlakyTest { + int bugId() default -1; + } + """ + ) + private val annotationsFlakyTestStub: TestFile = + java( + """ + package android.platform.test.annotations; + + public @interface FlakyTest { + int bugId() default -1; + } + """ + ) + private val stubs = arrayOf(filtersFlakyTestStub, annotationsFlakyTestStub) +} diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java index 3a6b3628e937..e6b2c2f9c7ed 100644 --- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java +++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java @@ -350,7 +350,7 @@ public final class DynamicColor { if (bgDynamicColor != null) { final boolean bgHasBg = bgDynamicColor.background != null && bgDynamicColor.background.apply(scheme) - == null; + != null; final double standardRatio = Contrast.ratioOfTones(tone.apply(scheme), bgDynamicColor.tone.apply(scheme)); if (decreasingContrast) { @@ -358,15 +358,15 @@ public final class DynamicColor { Contrast.ratioOfTones( toneMinContrast.apply(scheme), bgDynamicColor.toneMinContrast.apply(scheme)); - minRatio = bgHasBg ? 1.0 : minContrastRatio; + minRatio = bgHasBg ? minContrastRatio : 1.0; maxRatio = standardRatio; } else { final double maxContrastRatio = Contrast.ratioOfTones( toneMaxContrast.apply(scheme), bgDynamicColor.toneMaxContrast.apply(scheme)); - minRatio = !bgHasBg ? 1.0 : min(maxContrastRatio, standardRatio); - maxRatio = !bgHasBg ? 21.0 : max(maxContrastRatio, standardRatio); + minRatio = bgHasBg ? min(maxContrastRatio, standardRatio) : 1.0; + maxRatio = bgHasBg ? max(maxContrastRatio, standardRatio) : 21.0; } } diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index ce88d5b2f60f..6a18b3dcfd82 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -31,8 +31,7 @@ <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bizkor kargatzen"</string> <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mantso kargatzen"</string> <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargatzea optimizatu da bateria ez kaltetzeko"</string> - <!-- no translation found for keyguard_plugged_in_incompatible_charger (5712938022567388098) --> - <skip /> + <string name="keyguard_plugged_in_incompatible_charger" msgid="5712938022567388098">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargagailua ez da bateragarria"</string> <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Desblokeatzeko, sakatu Menua."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string> <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ez dago SIMik"</string> diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml index 80bd0bfaec42..2f295f745549 100644 --- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml @@ -31,8 +31,7 @@ <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"En recharge rapide : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"En recharge lente : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge optimisée pour protéger la pile"</string> - <!-- no translation found for keyguard_plugged_in_incompatible_charger (5712938022567388098) --> - <skip /> + <string name="keyguard_plugged_in_incompatible_charger" msgid="5712938022567388098">"<xliff:g id="PERCENTAGE">%s</xliff:g> • chargeur incompatible"</string> <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur la touche Menu pour déverrouiller l\'appareil."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string> <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune carte SIM"</string> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index b2058a182344..9dd5c5d24ee7 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -31,8 +31,7 @@ <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 고속 충전 중"</string> <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 저속 충전 중"</string> <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 배터리 보호를 위해 충전 최적화됨"</string> - <!-- no translation found for keyguard_plugged_in_incompatible_charger (5712938022567388098) --> - <skip /> + <string name="keyguard_plugged_in_incompatible_charger" msgid="5712938022567388098">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 호환되지 않는 충전기"</string> <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"잠금 해제하려면 메뉴를 누르세요."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"네트워크 잠김"</string> <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM 없음"</string> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 51f507cfeddb..11b4d79925c6 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -56,7 +56,7 @@ <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging optimized to protect battery</string> <!-- When the lock screen is showing and the phone plugged in with incompatible charger. --> - <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Incompatible charging</string> + <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Issue with charging accessory</string> <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock. This is shown in small font at the bottom. --> <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string> diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml index 75c82867884f..a677c12ced7b 100644 --- a/packages/SystemUI/res-product/values/strings.xml +++ b/packages/SystemUI/res-product/values/strings.xml @@ -122,6 +122,12 @@ Try again in <xliff:g id="number">%3$d</xliff:g> seconds. </string> + <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> + <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string> + <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> + <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string> + <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> + <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string> <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> <string name="global_action_lock_message" product="default">Unlock your phone for more options</string> @@ -134,4 +140,7 @@ <string name="media_transfer_playing_this_device" product="default">Playing on this phone</string> <!-- Text informing the user that their media is now playing on this tablet device. [CHAR LIMIT=50] --> <string name="media_transfer_playing_this_device" product="tablet">Playing on this tablet</string> + + + </resources> diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml index 58fe368ce4e1..97bd18e0442b 100644 --- a/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml +++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml @@ -27,7 +27,7 @@ <shape android:shape="rectangle"> <corners android:radius="@dimen/magnifier_outer_corner_radius" /> <stroke - android:color="@android:color/black" + android:color="@color/magnification_drag_handle_stroke" android:width="@dimen/magnifier_stroke_width"/> </shape> </item> diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml index a52e8053d8a0..66617e16b33a 100644 --- a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml +++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml @@ -16,7 +16,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <stroke - android:color="@android:color/black" + android:color="@color/magnification_drag_handle_stroke" android:width="@dimen/magnifier_stroke_width"/> <corners android:radius="@dimen/magnifier_corner_radius" /> <solid android:color="@color/magnification_border_color" /> diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change.xml new file mode 100644 index 000000000000..e367f50632a9 --- /dev/null +++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change.xml @@ -0,0 +1,23 @@ +<?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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <stroke + android:color="@color/magnification_border_color" + android:width="@dimen/magnifier_stroke_width"/> + <corners android:radius="@dimen/magnifier_corner_radius" /> + <solid android:color="@color/magnification_drag_handle_background_change" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_move_magnification.xml b/packages/SystemUI/res/drawable/ic_move_magnification.xml index 641bb4381fc8..079600734bc8 100644 --- a/packages/SystemUI/res/drawable/ic_move_magnification.xml +++ b/packages/SystemUI/res/drawable/ic_move_magnification.xml @@ -20,6 +20,6 @@ android:viewportHeight="24" android:tint="?attr/colorControlNormal"> <path - android:fillColor="@color/magnification_drag_handle_tint" + android:fillColor="@color/magnification_drag_handle_stroke" android:pathData="M12,15Q10.75,15 9.875,14.125Q9,13.25 9,12Q9,10.75 9.875,9.875Q10.75,9 12,9Q13.25,9 14.125,9.875Q15,10.75 15,12Q15,13.25 14.125,14.125Q13.25,15 12,15ZM12,22 L7.75,17.75 9.15,16.35 12,19.15 14.85,16.35 16.25,17.75ZM6.25,16.25 L2,12 6.25,7.75 7.65,9.15 4.85,12 7.65,14.85ZM9.15,7.65 L7.75,6.25 12,2 16.25,6.25 14.85,7.65 12,4.85ZM17.75,16.25 L16.35,14.85 19.15,12 16.35,9.15 17.75,7.75 22,12Z"/> </vector> diff --git a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml new file mode 100644 index 000000000000..de0a6201cb09 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml @@ -0,0 +1,25 @@ +<?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 + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <!-- gradient from 25% in the center to 100% at edges --> + <gradient + android:type="radial" + android:gradientRadius="40%p" + android:startColor="#AE000000" + android:endColor="#00000000" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml index c54c4e48d13d..a4aeba1dbcd6 100644 --- a/packages/SystemUI/res/layout/media_recommendation_view.xml +++ b/packages/SystemUI/res/layout/media_recommendation_view.xml @@ -22,9 +22,10 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:translationZ="0dp" - android:scaleType="centerCrop" + android:scaleType="matrix" android:adjustViewBounds="true" android:clipToOutline="true" + android:layerType="hardware" android:background="@drawable/bg_smartspace_media_item"/> <!-- App icon --> diff --git a/packages/SystemUI/res/layout/window_magnification_settings_view.xml b/packages/SystemUI/res/layout/window_magnification_settings_view.xml index 7dfe7c4c72be..ae0f8f46599d 100644 --- a/packages/SystemUI/res/layout/window_magnification_settings_view.xml +++ b/packages/SystemUI/res/layout/window_magnification_settings_view.xml @@ -21,7 +21,9 @@ android:layout_height="wrap_content" android:background="@drawable/accessibility_magnification_setting_view_bg" android:orientation="vertical" - android:padding="@dimen/magnification_setting_background_padding"> + android:padding="@dimen/magnification_setting_background_padding" + android:focusable="true" + android:contentDescription="@string/accessibility_magnification_settings_panel_description"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index be9ef9debc82..f26542690047 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kennisgewingskerm."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Vinnige instellings."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kitsinstellings en kennisgewingskerm."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sluitskerm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Werksluitskerm"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Maak toe"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 03925f72a8fb..4ec413e3a9a5 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مركز الإشعارات."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"الإعدادات السريعة."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"\"الإعدادات السريعة\" و\"مركز الإشعارات\""</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة القفل."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"شاشة قفل بيانات العمل"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"إغلاق"</string> @@ -695,7 +694,7 @@ <string name="right_keycode" msgid="2480715509844798438">"رمز مفتاح اليمين"</string> <string name="left_icon" msgid="5036278531966897006">"رمز اليسار"</string> <string name="right_icon" msgid="1103955040645237425">"رمز اليمين"</string> - <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة الميزات."</string> + <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة المربّعات"</string> <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"اضغط باستمرار مع السحب لإعادة ترتيب الميزات."</string> <string name="drag_to_remove_tiles" msgid="4682194717573850385">"اسحب هنا للإزالة"</string> <string name="drag_to_remove_disabled" msgid="933046987838658850">"الحدّ الأدنى من عدد المربعات الذي تحتاج إليه هو <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"التبديل إلى الملف الشخصي للعمل"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"إغلاق"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"إعدادات شاشة القفل"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"لا يتوفّر اتصال Wi-Fi."</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"استخدام الكاميرا محظور."</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخدام الكاميرا والميكروفون محظور."</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"استخدام الميكروفون محظور."</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"وضع الأولوية مفعّل."</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"ميزة لفت انتباه \"مساعد Google\" مفعّلة."</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 9507cdaf7f4f..ae2f1e2286b3 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"জাননী পেনেল।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিং।"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ক্ষিপ্ৰ ছেটিং জাননী পেনেল।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"বন্ধ স্ক্ৰীন।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ লক স্ক্ৰীন"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index fcee2e14cd9e..33496748d751 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildiriş kölgəsi."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tez ayarlar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Sürətli ayarlar və Bildiriş göstərişi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilid ekranı."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekran kilidi"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Qapadın"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 12ce25951383..dbfb012319b8 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Цень апавяшчэння.."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Хуткія налады."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Хуткія налады і шчыток апавяшчэнняў."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блакіроўкі."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Экран блакіроўкі дзейнасці"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыць"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Пераключыцца на працоўны профіль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыць"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Налады экрана блакіроўкі"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Сетка Wi-Fi недаступная"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблакіравана"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера і мікрафон заблакіраваны"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрафон заблакіраваны"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Прыярытэтны рэжым уключаны"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Памочнік гатовы выконваць каманды"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 9ba041eae4d2..e87b628ae8b3 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Падащ панел с известия."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Бързи настройки."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Падащ панел с бързи настройки и известия."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заключване на екрана."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Заключен екран на служебния профил"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Затваряне"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index dbc3a52b8151..2a84e59006ed 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"বিজ্ঞপ্তি শেড৷"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"দ্রুত সেটিংস৷"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"দ্রুত সেটিংস এবং বিজ্ঞপ্তি শেড।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"লক স্ক্রিন।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কর্মস্থলের স্ক্রিন লক"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ করুন"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"অফিস প্রোফাইলে পাল্টে নিন"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ করুন"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"লক স্ক্রিন সেটিংস"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ওয়াই-ফাই উপলভ্য নয়"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ক্যামেরার অ্যাক্সেস ব্লক করা আছে"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\'প্রায়োরিটি\' মোড চালু করা আছে"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"অ্যাসিস্ট্যান্ট আপনার কথা শোনার জন্য চালু করা আছে"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 8d4a0dd9b42b..e73eab959822 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -198,7 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obavještenja sa sjenčenjem."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string> - <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Brze postavke i zaslon obavijesti."</string> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Brze postavke i lokacija za obavještenja."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Zaključan ekran radnog profila"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zatvori"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index cc878950c0d3..66d20e4889d0 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Àrea de notificacions"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuració ràpida"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuració ràpida i àrea de notificacions."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueig"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueig per a la feina"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Tanca"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Canvia al perfil de treball"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tanca"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Configuració pantalla de bloqueig"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"No hi ha cap Wi‑Fi disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El mode Prioritat està activat"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"L\'Assistent està activat"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index e07a89215df3..e61a4d0ae672 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel oznámení."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rychlé nastavení."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Rychlé nastavení a panel oznámení"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Obrazovka uzamčení"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Obrazovka uzamčení pracovního profilu"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zavřít"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 4b10ddfade91..aa6a480373e2 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notifikationspanel."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kvikmenu."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kvikmenu og notifikationspanel."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskærm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låseskærm til arbejde"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Luk"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skift til arbejdsprofil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Luk"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Indstillinger for låseskærm"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ikke tilgængeligt"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetstilstand er aktiveret"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent lytter"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index f8c02e3c496a..621788aa993c 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Benachrichtigungsleiste"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Schnelleinstellungen"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Schnelleinstellungen und Benachrichtigungsleiste."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sperrbildschirm"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Sperrbildschirm für Arbeitsprofil"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Schließen"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index f2fb5b89955b..d81cedb2e400 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Πλαίσιο σκίασης ειδοποιήσεων."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Γρήγορες ρυθμίσεις."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Γρήγορες ρυθμίσεις και πλαίσιο σκίασης ειδοποιήσεων."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Οθόνη κλειδώματος"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Οθόνη κλειδωμένης εργασίας"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Κλείσιμο"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 81682b583904..44b56de971f3 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuración rápida y panel de notificaciones."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla bloqueada del perfil de trabajo"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Config. de pantalla de bloqueo"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi no disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La cámara está bloqueada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micrófono está bloqueado"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El modo de prioridad está activado"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistente está prestando atención"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 526743ae0ed8..9080c5869c53 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ajustes rápidos"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ajustes rápidos y pantalla de notificaciones."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueo para el perfil de trabajo"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string> @@ -1019,7 +1018,7 @@ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string> <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string> - <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectada temporalmente"</string> + <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectado temporalmente"</string> <string name="mobile_data_poor_connection" msgid="819617772268371434">"Conexión inestable"</string> <string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string> <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Ajustes de pantalla de bloqueo"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Red Wi-Fi no disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridad activado"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"El Asistente está activado"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 9388a14295c9..9ce7dbf74354 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Märguande vari."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kiirseaded."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kiirseaded ja märguandeala."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kuva lukustamine."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Töö lukustuskuva"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Sulgemine"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Lülitu tööprofiilile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sule"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Lukustuskuva seaded"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi pole saadaval"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteetne režiim on sisse lülitatud"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent on aktiveeritud"</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 84f2d0cf394c..d37afbabb58c 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -616,84 +616,48 @@ <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Jakinarazpenak"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Lasterbideak"</string> <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Aldatu tekl. diseinua"</string> - <!-- no translation found for keyboard_shortcut_clear_text (4679927133259287577) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_title (1156178106617830429) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_hint (5982623262974326746) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_no_result (6819302191660875501) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_system (1151182120757052669) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_input (5440558509904296233) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_open_apps (1450959949739257562) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_current_app (2011953559133734491) --> - <skip /> - <!-- no translation found for group_system_access_notification_shade (7116898151485382275) --> - <skip /> - <!-- no translation found for group_system_full_screenshot (7389040853798023211) --> - <skip /> - <!-- no translation found for group_system_access_system_app_shortcuts (4421497579210445641) --> - <skip /> - <!-- no translation found for group_system_go_back (8838454003680364227) --> - <skip /> - <!-- no translation found for group_system_access_home_screen (1857344316928441909) --> - <skip /> - <!-- no translation found for group_system_overview_open_apps (6897128761003265350) --> - <skip /> - <!-- no translation found for group_system_cycle_forward (9202444850838205990) --> - <skip /> - <!-- no translation found for group_system_cycle_back (5163464503638229131) --> - <skip /> - <!-- no translation found for group_system_access_all_apps_search (488070738028991753) --> - <skip /> - <!-- no translation found for group_system_hide_reshow_taskbar (3809304065624351131) --> - <skip /> - <!-- no translation found for group_system_access_system_settings (7961639365383008053) --> - <skip /> - <!-- no translation found for group_system_access_google_assistant (1186152943161483864) --> - <skip /> - <!-- no translation found for group_system_lock_screen (7391191300363416543) --> - <skip /> - <!-- no translation found for group_system_quick_memo (2914234890158583919) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_system_multitasking (1065232949510862593) --> - <skip /> - <!-- no translation found for system_multitasking_rhs (6593269428880305699) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (8839380725557952846) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (1962084334200006297) --> - <skip /> - <!-- no translation found for system_multitasking_replace (844285282472557186) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_input (6888282716546625610) --> - <skip /> - <!-- no translation found for input_switch_input_language_next (3394291576873633793) --> - <skip /> - <!-- no translation found for input_switch_input_language_previous (8823659252918609216) --> - <skip /> - <!-- no translation found for input_access_emoji (8105642858900406351) --> - <skip /> - <!-- no translation found for input_access_voice_typing (7291201476395326141) --> - <skip /> + <string name="keyboard_shortcut_clear_text" msgid="4679927133259287577">"Garbitu testua"</string> + <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Lasterbideak"</string> + <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Bilatu lasterbideak"</string> + <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ez da aurkitu lasterbiderik"</string> + <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> + <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Sarrera"</string> + <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Irekitako aplikazioak"</string> + <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Uneko aplikazioa"</string> + <string name="group_system_access_notification_shade" msgid="7116898151485382275">"Atzitu jakinarazpenen panela"</string> + <string name="group_system_full_screenshot" msgid="7389040853798023211">"Atera pantaila osoaren argazki bat"</string> + <string name="group_system_access_system_app_shortcuts" msgid="4421497579210445641">"Atzitu sistemaren edo aplikazioetarako lasterbideen zerrenda"</string> + <string name="group_system_go_back" msgid="8838454003680364227">"Atzera: itzuli aurreko egoerara (atzera egiteko botoia)"</string> + <string name="group_system_access_home_screen" msgid="1857344316928441909">"Atzitu hasierako pantaila"</string> + <string name="group_system_overview_open_apps" msgid="6897128761003265350">"Ikusi irekitako aplikazioen ikuspegi orokorra"</string> + <string name="group_system_cycle_forward" msgid="9202444850838205990">"Joan azken aplikazioetako batetik bestera (aurrera)"</string> + <string name="group_system_cycle_back" msgid="5163464503638229131">"Joan azken aplikazioetako batetik bestera (atzera)"</string> + <string name="group_system_access_all_apps_search" msgid="488070738028991753">"Atzitu aplikazio guztien zerrenda eta bilatu (adibidez, bilatzeko aukeraren edo Exekutatzeko tresna aplikazioaren bidez)"</string> + <string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"Ezkutatu eta erakutsi (berriro) zereginen barra"</string> + <string name="group_system_access_system_settings" msgid="7961639365383008053">"Atzitu sistemaren ezarpenak"</string> + <string name="group_system_access_google_assistant" msgid="1186152943161483864">"Atzitu Google-ren Laguntzailea"</string> + <string name="group_system_lock_screen" msgid="7391191300363416543">"Blokeatu pantaila"</string> + <string name="group_system_quick_memo" msgid="2914234890158583919">"Ireki Oharrak aplikazioa oharrak bizkor idazteko"</string> + <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Zereginen aldibereko sistemaren exekuzioa"</string> + <string name="system_multitasking_rhs" msgid="6593269428880305699">"Sartu pantaila zatituaren eskuineko aldean uneko aplikazioarekin"</string> + <string name="system_multitasking_lhs" msgid="8839380725557952846">"Sartu pantaila zatituaren ezkerreko aldean uneko aplikazioarekin"</string> + <string name="system_multitasking_full_screen" msgid="1962084334200006297">"Aldatu pantaila zatitutik pantaila osora"</string> + <string name="system_multitasking_replace" msgid="844285282472557186">"Pantaila zatituan zaudela: ordeztu aplikazio bat beste batekin"</string> + <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Sarrera"</string> + <string name="input_switch_input_language_next" msgid="3394291576873633793">"Aldatu idazteko hizkuntza (hurrengo hizkuntza)"</string> + <string name="input_switch_input_language_previous" msgid="8823659252918609216">"Aldatu idazteko hizkuntza (aurreko hizkuntza)"</string> + <string name="input_access_emoji" msgid="8105642858900406351">"Atzitu emojiak"</string> + <string name="input_access_voice_typing" msgid="7291201476395326141">"Atzitu ahozko idazketa"</string> <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Aplikazioak"</string> <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Laguntzailea"</string> - <!-- no translation found for keyboard_shortcut_group_applications_browser (7328131901589876868) --> - <skip /> + <string name="keyboard_shortcut_group_applications_browser" msgid="7328131901589876868">"Ireki arakatzailea (Chrome, modu lehenetsian)"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Kontaktuak"</string> - <!-- no translation found for keyboard_shortcut_group_applications_email (7480359963463803511) --> - <skip /> + <string name="keyboard_shortcut_group_applications_email" msgid="7480359963463803511">"Ireki posta elektronikoa (Gmail, modu lehenetsian)"</string> <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMSak"</string> <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musika"</string> <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> - <!-- no translation found for keyboard_shortcut_group_applications_calculator (6316043911946540137) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_applications_maps (7312554713993114342) --> - <skip /> + <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Ireki Kalkulagailua"</string> + <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Ireki Maps"</string> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ez molestatzeko modua"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Bolumen-botoietarako lasterbidea"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -856,12 +820,9 @@ <string name="privacy_type_media_projection" msgid="8136723828804251547">"pantaila-grabaketa"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string> - <!-- no translation found for font_scaling_dialog_title (6273107303850248375) --> - <skip /> - <!-- no translation found for font_scaling_smaller (1012032217622008232) --> - <skip /> - <!-- no translation found for font_scaling_larger (5476242157436806760) --> - <skip /> + <string name="font_scaling_dialog_title" msgid="6273107303850248375">"Letraren tamaina"</string> + <string name="font_scaling_smaller" msgid="1012032217622008232">"Txikitu"</string> + <string name="font_scaling_larger" msgid="5476242157436806760">"Handitu"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string> <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Handitu"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index bafee640bcff..9bc513e80856 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مجموعه اعلان."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"تنظیمات سریع."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"تنظیمات فوری و کشوی اعلانات."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"صفحه قفل."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"صفحه قفل کاری"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"بستن"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 4097e76699c6..4c3962e249bc 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ilmoitusalue."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Pika-asetukset."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Pika-asetukset ja ilmoitusalue"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lukitse näyttö."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Työlukitusnäyttö"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Sulje"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 47974b254362..05dec17d3b3b 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -616,84 +616,48 @@ <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Raccourcis clavier"</string> <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Changer la disposition du clavier"</string> - <!-- no translation found for keyboard_shortcut_clear_text (4679927133259287577) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_title (1156178106617830429) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_hint (5982623262974326746) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_no_result (6819302191660875501) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_system (1151182120757052669) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_input (5440558509904296233) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_open_apps (1450959949739257562) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_current_app (2011953559133734491) --> - <skip /> - <!-- no translation found for group_system_access_notification_shade (7116898151485382275) --> - <skip /> - <!-- no translation found for group_system_full_screenshot (7389040853798023211) --> - <skip /> - <!-- no translation found for group_system_access_system_app_shortcuts (4421497579210445641) --> - <skip /> - <!-- no translation found for group_system_go_back (8838454003680364227) --> - <skip /> - <!-- no translation found for group_system_access_home_screen (1857344316928441909) --> - <skip /> - <!-- no translation found for group_system_overview_open_apps (6897128761003265350) --> - <skip /> - <!-- no translation found for group_system_cycle_forward (9202444850838205990) --> - <skip /> - <!-- no translation found for group_system_cycle_back (5163464503638229131) --> - <skip /> - <!-- no translation found for group_system_access_all_apps_search (488070738028991753) --> - <skip /> - <!-- no translation found for group_system_hide_reshow_taskbar (3809304065624351131) --> - <skip /> - <!-- no translation found for group_system_access_system_settings (7961639365383008053) --> - <skip /> - <!-- no translation found for group_system_access_google_assistant (1186152943161483864) --> - <skip /> - <!-- no translation found for group_system_lock_screen (7391191300363416543) --> - <skip /> - <!-- no translation found for group_system_quick_memo (2914234890158583919) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_system_multitasking (1065232949510862593) --> - <skip /> - <!-- no translation found for system_multitasking_rhs (6593269428880305699) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (8839380725557952846) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (1962084334200006297) --> - <skip /> - <!-- no translation found for system_multitasking_replace (844285282472557186) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_input (6888282716546625610) --> - <skip /> - <!-- no translation found for input_switch_input_language_next (3394291576873633793) --> - <skip /> - <!-- no translation found for input_switch_input_language_previous (8823659252918609216) --> - <skip /> - <!-- no translation found for input_access_emoji (8105642858900406351) --> - <skip /> - <!-- no translation found for input_access_voice_typing (7291201476395326141) --> - <skip /> + <string name="keyboard_shortcut_clear_text" msgid="4679927133259287577">"Effacer le texte"</string> + <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Raccourcis"</string> + <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Recherchez des raccourcis"</string> + <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Aucun raccourci trouvé"</string> + <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Système"</string> + <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Entrée"</string> + <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Ouvrir applis"</string> + <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Appli actuelle"</string> + <string name="group_system_access_notification_shade" msgid="7116898151485382275">"Accéder au volet de notification"</string> + <string name="group_system_full_screenshot" msgid="7389040853798023211">"Prendre une capture d\'écran complète"</string> + <string name="group_system_access_system_app_shortcuts" msgid="4421497579210445641">"Accéder à la liste des raccourcis du système/des applications"</string> + <string name="group_system_go_back" msgid="8838454003680364227">"Retour : retour à l\'état précédent (bouton précédent)"</string> + <string name="group_system_access_home_screen" msgid="1857344316928441909">"Accéder à l\'écran d\'accueil"</string> + <string name="group_system_overview_open_apps" msgid="6897128761003265350">"Aperçu des applications ouvertes"</string> + <string name="group_system_cycle_forward" msgid="9202444850838205990">"Parcourir les applications récentes (avancer)"</string> + <string name="group_system_cycle_back" msgid="5163464503638229131">"Parcourir les applications récentes (retour)"</string> + <string name="group_system_access_all_apps_search" msgid="488070738028991753">"Accéder à la liste des applis et à la recherche (recherche/lanceur)"</string> + <string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"Masquer et (ré)afficher la barre des tâches"</string> + <string name="group_system_access_system_settings" msgid="7961639365383008053">"Accéder aux paramètres système"</string> + <string name="group_system_access_google_assistant" msgid="1186152943161483864">"Accéder à l\'Assistant Google"</string> + <string name="group_system_lock_screen" msgid="7391191300363416543">"Écran de verrouillage"</string> + <string name="group_system_quick_memo" msgid="2914234890158583919">"Ouvrir l\'application de prise de notes pour prendre des notes rapides"</string> + <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitâche du système"</string> + <string name="system_multitasking_rhs" msgid="6593269428880305699">"Passer à l\'écran partagé avec l\'application actuelle à droite"</string> + <string name="system_multitasking_lhs" msgid="8839380725557952846">"Passer à l\'écran partagé avec l\'application actuelle à gauche"</string> + <string name="system_multitasking_full_screen" msgid="1962084334200006297">"Passer de l\'écran partagé au plein écran"</string> + <string name="system_multitasking_replace" msgid="844285282472557186">"En mode d\'écran partagé : remplacer une application par une autre"</string> + <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrée"</string> + <string name="input_switch_input_language_next" msgid="3394291576873633793">"Changer la langue d\'entrée (langue suivante)"</string> + <string name="input_switch_input_language_previous" msgid="8823659252918609216">"Changer la langue d\'entrée (langue précédente)"</string> + <string name="input_access_emoji" msgid="8105642858900406351">"Accéder aux émojis"</string> + <string name="input_access_voice_typing" msgid="7291201476395326141">"Accéder à l\'entrée vocale"</string> <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Applications"</string> <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Assistance"</string> - <!-- no translation found for keyboard_shortcut_group_applications_browser (7328131901589876868) --> - <skip /> + <string name="keyboard_shortcut_group_applications_browser" msgid="7328131901589876868">"Navigateur (Chrome par défaut)"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Contacts"</string> - <!-- no translation found for keyboard_shortcut_group_applications_email (7480359963463803511) --> - <skip /> + <string name="keyboard_shortcut_group_applications_email" msgid="7480359963463803511">"Courriel (Gmail par défaut)"</string> <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Messages texte"</string> <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musique"</string> <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string> - <!-- no translation found for keyboard_shortcut_group_applications_calculator (6316043911946540137) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_applications_maps (7312554713993114342) --> - <skip /> + <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculatrice"</string> + <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne pas déranger"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Raccourci des boutons de volume"</string> <string name="battery" msgid="769686279459897127">"Pile"</string> @@ -856,12 +820,9 @@ <string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement d\'écran"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string> - <!-- no translation found for font_scaling_dialog_title (6273107303850248375) --> - <skip /> - <!-- no translation found for font_scaling_smaller (1012032217622008232) --> - <skip /> - <!-- no translation found for font_scaling_larger (5476242157436806760) --> - <skip /> + <string name="font_scaling_dialog_title" msgid="6273107303850248375">"Taille de police"</string> + <string name="font_scaling_smaller" msgid="1012032217622008232">"Rapetisser"</string> + <string name="font_scaling_larger" msgid="5476242157436806760">"Agrandir"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string> <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Effectuer un zoom avant"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 7e2badad012d..0e089c893eaf 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Réglages rapides"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Réglages rapides et volet des notifications."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Écran de verrouillage du profil professionnel"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fermer"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Paramètres écran de verrouillage"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Prioritaire activé"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant à l\'écoute"</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 8ff9b06349af..ea532f5f82af 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel despregable"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuración rápida e panel despregable."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueo do perfil de traballo"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Pechar"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar ao perfil de traballo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Pechar"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Configuración pantalla bloqueo"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi non dispoñible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"O modo de prioridade está activado"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"A atención do Asistente está activada"</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index d1422ba1874d..3f2b494bc4b2 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ઝડપી સેટિંગ અને નોટિફિકેશન શેડ."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"કાર્ય લૉક સ્ક્રીન"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"બંધ કરો"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"બંધ કરો"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"લૉક સ્ક્રીનના સેટિંગ"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"કૅમેરા બ્લૉક કરેલો છે"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"માઇક્રોફોન બ્લૉક કરેલો છે"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"પ્રાધાન્યતા મોડ ચાલુ છે"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant સક્રિય છે"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 0d08dcd0a7e2..c49861bf4f70 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"त्वरित सेटिंग."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"क्विक सेटिंग और नोटिफ़िकेशन शेड."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"वर्क लॉक स्क्रीन"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करें"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index fadc88d1cf8f..b9c606724ccf 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Értesítési felület."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Gyorsbeállítások."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Gyorsbeállítások és értesítési terület"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lezárási képernyő."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Munka lezárási képernyővel"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Bezárás"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Váltás munkaprofilra"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Bezárás"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Lezárási képernyő beállításai"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Nem áll rendelkezésre Wi-Fi"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritás mód bekapcsolva"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"A Segéd figyel"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 22877cf4c4c4..018120a7f28a 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ծանուցումների վահանակ:"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Արագ կարգավորումներ:"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Արագ կարգավորումներ և ծանուցումների վահանակ։"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Էկրանի կողպում:"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Աշխատանքային պրոֆիլի կողպէկրան"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Փակել"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Անցնել աշխատանքային պրոֆիլ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Փակել"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Կողպէկրանի կարգավորումներ"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ցանց հասանելի չէ"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Տեսախցիկն արգելափակված է"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Տեսախցիկն ու խոսափողը արգելափակված են"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Խոսափողն արգելափակված է"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Առաջնահերթության ռեժիմը միացված է"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Օգնականը լսում է"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 262d0e1bc17f..d76d2ffcfc0d 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bayangan pemberitahuan."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setelan cepat."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Setelan cepat dan Menu notifikasi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Layar kunci."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Layar kunci kantor"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Beralih ke profil kerja"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Setelan layar kunci"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera diblokir"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode prioritas diaktifkan"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asisten sedang memerhatikan"</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 7bdc66c9bc21..228052440538 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Tilkynningasvæði."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Flýtistillingar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Flýtistillingar og tilkynningagluggi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lásskjár."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vinnulásskjár"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Loka"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skipta yfir í vinnusnið"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Loka"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Stillingar fyrir lásskjá"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ekki til staðar"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Kveikt er á forgangsstillingu"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Hjálparinn er að hlusta"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index bc983ffb07fe..873138209b9d 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1110,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa a profilo di lavoro"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Impostazioni schermata di blocco"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modalità priorità attivata"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"L\'assistente è attivo"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 859435f1b92a..8946db2bea31 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"לוח התראות."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"הגדרות מהירות."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"הגדרות מהירות ולוח ההתראות."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"מסך נעילה."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"מסך נעילה של עבודה"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"סגירה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index ca29664f9c5e..d5b96d5f5fea 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知シェード"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"クイック設定"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"クイック設定と通知シェード。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ロック画面"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"仕事用プロファイルのロック画面"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"閉じる"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 4e40a737c359..54101b13de95 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"შეტყობინებების ფარდა"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"სწრაფი პარამეტრები"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"სწრაფი პარამეტრები და შეტყობინებების ფარდა"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ეკრანის დაბლოკვა."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"სამსახურის ჩაკეტილი ეკრანი"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"დახურვა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 459237bbf514..dce96820cbd2 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Хабарландыру тақтасы"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Жылдам параметрлер."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Жылдам параметрлер мен хабарландыру тақтасы."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Бекіту экраны."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Әрекетті құлыптау экраны"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Жабу"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жұмыс профиліне ауысу"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабу"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Экран құлпының параметрлері"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi қолжетімсіз."</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера бөгелген."</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера мен микрофон бөгелген."</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон бөгелген."</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\"Маңызды\" режимі қосулы."</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant қосулы."</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index f3452837d934..ef20217fee53 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ពណ៌ការជូនដំណឹង"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ការកំណត់រហ័ស។"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ការកំណត់រហ័ស និងផ្ទាំងជូនដំណឹង។"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ចាក់សោអេក្រង់។"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"អេក្រង់ចាក់សោលក្ខណៈការងារ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"បិទ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 6e22f3659eb8..c830e847923a 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಯ ಪರದೆ."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್ ಸ್ಕ್ರೀನ್."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ಮುಚ್ಚು"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index f7a6dfbf2191..b33168f9e0ea 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"알림 세부정보"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"빠른 설정"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"빠른 설정 및 알림 창입니다."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"화면을 잠급니다."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"업무용 잠금 화면"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"닫기"</string> @@ -616,84 +615,48 @@ <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"알림"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"단축키"</string> <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"키보드 레이아웃 전환"</string> - <!-- no translation found for keyboard_shortcut_clear_text (4679927133259287577) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_title (1156178106617830429) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_hint (5982623262974326746) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_list_no_result (6819302191660875501) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_system (1151182120757052669) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_input (5440558509904296233) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_open_apps (1450959949739257562) --> - <skip /> - <!-- no translation found for keyboard_shortcut_search_category_current_app (2011953559133734491) --> - <skip /> - <!-- no translation found for group_system_access_notification_shade (7116898151485382275) --> - <skip /> - <!-- no translation found for group_system_full_screenshot (7389040853798023211) --> - <skip /> - <!-- no translation found for group_system_access_system_app_shortcuts (4421497579210445641) --> - <skip /> - <!-- no translation found for group_system_go_back (8838454003680364227) --> - <skip /> - <!-- no translation found for group_system_access_home_screen (1857344316928441909) --> - <skip /> - <!-- no translation found for group_system_overview_open_apps (6897128761003265350) --> - <skip /> - <!-- no translation found for group_system_cycle_forward (9202444850838205990) --> - <skip /> - <!-- no translation found for group_system_cycle_back (5163464503638229131) --> - <skip /> - <!-- no translation found for group_system_access_all_apps_search (488070738028991753) --> - <skip /> - <!-- no translation found for group_system_hide_reshow_taskbar (3809304065624351131) --> - <skip /> - <!-- no translation found for group_system_access_system_settings (7961639365383008053) --> - <skip /> - <!-- no translation found for group_system_access_google_assistant (1186152943161483864) --> - <skip /> - <!-- no translation found for group_system_lock_screen (7391191300363416543) --> - <skip /> - <!-- no translation found for group_system_quick_memo (2914234890158583919) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_system_multitasking (1065232949510862593) --> - <skip /> - <!-- no translation found for system_multitasking_rhs (6593269428880305699) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (8839380725557952846) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (1962084334200006297) --> - <skip /> - <!-- no translation found for system_multitasking_replace (844285282472557186) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_input (6888282716546625610) --> - <skip /> - <!-- no translation found for input_switch_input_language_next (3394291576873633793) --> - <skip /> - <!-- no translation found for input_switch_input_language_previous (8823659252918609216) --> - <skip /> - <!-- no translation found for input_access_emoji (8105642858900406351) --> - <skip /> - <!-- no translation found for input_access_voice_typing (7291201476395326141) --> - <skip /> + <string name="keyboard_shortcut_clear_text" msgid="4679927133259287577">"텍스트 삭제"</string> + <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"단축키"</string> + <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"단축키 검색"</string> + <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"단축키 없음"</string> + <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"시스템"</string> + <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"입력"</string> + <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"열린 앱"</string> + <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"현재 앱"</string> + <string name="group_system_access_notification_shade" msgid="7116898151485382275">"알림 창에 액세스"</string> + <string name="group_system_full_screenshot" msgid="7389040853798023211">"전체 스크린샷 촬영"</string> + <string name="group_system_access_system_app_shortcuts" msgid="4421497579210445641">"시스템/앱 단축키 목록에 액세스"</string> + <string name="group_system_go_back" msgid="8838454003680364227">"뒤로: 이전 상태로 되돌아가기(뒤로 버튼)"</string> + <string name="group_system_access_home_screen" msgid="1857344316928441909">"홈 화면에 액세스"</string> + <string name="group_system_overview_open_apps" msgid="6897128761003265350">"열린 앱 개요"</string> + <string name="group_system_cycle_forward" msgid="9202444850838205990">"최근 앱 간 순환(앞으로)"</string> + <string name="group_system_cycle_back" msgid="5163464503638229131">"최근 앱 간 순환(뒤로)"</string> + <string name="group_system_access_all_apps_search" msgid="488070738028991753">"모든 앱 및 검색 목록(예: 검색/런처)에 액세스"</string> + <string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"태스크 바 숨김 및 다시 표시"</string> + <string name="group_system_access_system_settings" msgid="7961639365383008053">"시스템 설정에 액세스"</string> + <string name="group_system_access_google_assistant" msgid="1186152943161483864">"Google 어시스턴트에 액세스"</string> + <string name="group_system_lock_screen" msgid="7391191300363416543">"잠금 화면"</string> + <string name="group_system_quick_memo" msgid="2914234890158583919">"빠른 메모를 위해 노트 앱 불러오기"</string> + <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"시스템 멀티태스킹"</string> + <string name="system_multitasking_rhs" msgid="6593269428880305699">"현재 앱을 오른쪽으로 보내는 화면 분할 입력"</string> + <string name="system_multitasking_lhs" msgid="8839380725557952846">"현재 앱을 왼쪽으로 보내는 화면 분할 입력"</string> + <string name="system_multitasking_full_screen" msgid="1962084334200006297">"화면 분할에서 전체 화면으로 전환"</string> + <string name="system_multitasking_replace" msgid="844285282472557186">"화면 분할 중: 다른 앱으로 바꾸기"</string> + <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"입력"</string> + <string name="input_switch_input_language_next" msgid="3394291576873633793">"입력 언어 전환(다음 언어)"</string> + <string name="input_switch_input_language_previous" msgid="8823659252918609216">"입력 언어 전환(이전 언어)"</string> + <string name="input_access_emoji" msgid="8105642858900406351">"이모티콘에 액세스"</string> + <string name="input_access_voice_typing" msgid="7291201476395326141">"음성 입력에 액세스"</string> <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"애플리케이션"</string> <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"지원"</string> - <!-- no translation found for keyboard_shortcut_group_applications_browser (7328131901589876868) --> - <skip /> + <string name="keyboard_shortcut_group_applications_browser" msgid="7328131901589876868">"브라우저(Chrome을 기본값으로 설정)"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"연락처"</string> - <!-- no translation found for keyboard_shortcut_group_applications_email (7480359963463803511) --> - <skip /> + <string name="keyboard_shortcut_group_applications_email" msgid="7480359963463803511">"이메일(Gmail을 기본값으로 설정)"</string> <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string> <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"음악"</string> <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"캘린더"</string> - <!-- no translation found for keyboard_shortcut_group_applications_calculator (6316043911946540137) --> - <skip /> - <!-- no translation found for keyboard_shortcut_group_applications_maps (7312554713993114342) --> - <skip /> + <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"계산기"</string> + <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"지도"</string> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"방해 금지 모드"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"볼륨 버튼 단축키"</string> <string name="battery" msgid="769686279459897127">"배터리"</string> @@ -856,12 +819,9 @@ <string name="privacy_type_media_projection" msgid="8136723828804251547">"화면 녹화"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string> - <!-- no translation found for font_scaling_dialog_title (6273107303850248375) --> - <skip /> - <!-- no translation found for font_scaling_smaller (1012032217622008232) --> - <skip /> - <!-- no translation found for font_scaling_larger (5476242157436806760) --> - <skip /> + <string name="font_scaling_dialog_title" msgid="6273107303850248375">"글꼴 크기"</string> + <string name="font_scaling_smaller" msgid="1012032217622008232">"축소"</string> + <string name="font_scaling_larger" msgid="5476242157436806760">"확대"</string> <string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string> <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"확대"</string> @@ -1150,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"직장 프로필로 전환"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"닫기"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"잠금 화면 설정"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi를 사용할 수 없음"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"카메라 차단됨"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"카메라 및 마이크 차단됨"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"마이크 차단됨"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"우선순위 모드 설정됨"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"어시스턴트가 대기 중임"</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 3d6a94954113..d50e19743e05 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Билдирмелер тактасы."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Тез тууралоолор."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ыкчам параметрлер жана билдирмелер тактасы."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Кулпуланган экран."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Жумуштун кулпуланган экраны"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Жабуу"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 0b5b5de89bfd..41610493d10e 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ໜ້າຈໍແຈ້ງເຕືອນ."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ການຕັ້ງຄ່າດ່ວນ."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ການຕັ້ງຄ່າດ່ວນ ແລະ ເງົາການແຈ້ງເຕືອນ."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ລັອກໜ້າຈໍ."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ໜ້າຈໍລັອກວຽກ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ປິດ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index d607b178b1e0..b37478943665 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pranešimų gaubtas."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Spartieji nustatymai."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Spartieji nustatymai ir pranešimų skydelis."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Užrakinimo ekranas."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Darbo profilio užrakinimo ekranas"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Uždaryti"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 30ffd4bd19ca..f82bcd64b22e 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Paziņojumu panelis"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ātrie iestatījumi"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ātrie iestatījumi un paziņojumu panelis."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Bloķēšanas ekrāns."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Darba profila bloķēšanas ekrāns"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Aizvērt"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pārslēgties uz darba profilu"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Aizvērt"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Bloķēšanas ekrāna iestatījumi"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nav pieejams"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloķēta"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloķēts"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritātes režīms ir ieslēgts"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistents klausās"</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index cda4a856e176..64631c867c74 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"„Брзи поставки“ и „Панел со известувања“."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Работен заклучен екран"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Затвори"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Префрли се на работен профил"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Поставки за заклучен екран"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е достапно"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерата е блокирана"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофонот е блокиран"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетниот режим е вклучен"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Вниманието на „Помошникот“ е вклучено"</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 580241036d01..75633a284c9c 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"അറിയിപ്പ് ഷെയ്ഡ്."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ദ്രുത ക്രമീകരണങ്ങൾ."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"അറിയിപ്പ് ഷെയ്ഡിനുള്ള ദ്രുത ക്രമീകരണം."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ലോക്ക് സ്ക്രീൻ."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ഔദ്യോഗിക ലോക്ക് സ്ക്രീൻ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"അവസാനിപ്പിക്കുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 3e6405ce6678..c1be9f782916 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Мэдэгдлийн хураангуй самбар"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Шуурхай тохиргоо."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Шуурхай тохиргоо болон мэдэгдлийн хураангуй самбар."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Дэлгэц түгжих."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ажлын түгжигдсэн дэлгэц"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Хаах"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index f582a9fae40a..b729efc167b5 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"क्विक सेटिंग्ज."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"क्विक सेटिंग्ज आणि सूचना शेड."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"कार्य लॉक स्क्रीन"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करा"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइलवर स्विच करा"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करा"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"लॉक स्क्रीन सेटिंग्ज"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाय-फाय उपलब्ध नाही"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कॅमेरा ब्लॉक केला"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"मायक्रोफोन ब्लॉक केला"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राधान्य मोड सुरू आहे"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant चे लक्ष हे आता अॅक्टिव्ह आहे"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 4624a4ba1aae..9ed06362c359 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bidai pemberitahuan."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tetapan pantas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Tetapan pantas dan Bidai pemberitahuan."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kunci skrin."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrin kunci kerja"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 646348044639..88165a83589a 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"အကြောင်းကြားစာအကွက်"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"အမြန်လုပ် အပြင်အဆင်"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"‘အမြန်ဆက်တင်များ’ နှင့် ‘အကြောင်းကြားစာအကွက်’။"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"မျက်နှာပြင် သော့ပိတ်ရန်"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"အလုပ်သုံး လော့ခ်မျက်နှာပြင်"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ပိတ်ရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 94ebf2b9857a..33d87ead34df 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Varselskygge."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hurtiginnstillinger."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hurtiginnstillinger og varselpanelet"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskjerm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låseskjerm for arbeid"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Lukk"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index d16e91f68813..48e134bb27e4 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना कक्ष।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिङहरू"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"द्रुत सेटिङ तथा सूचना कक्ष।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"स्क्रीन बन्द गर्नुहोस्।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"कार्य प्रोफाइलको लक स्क्रिन"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"बन्द गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 995abb04ca9f..2f86231a4827 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meldingenpaneel."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snelle instellingen."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Snelle instellingen en meldingenpaneel."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelscherm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vergrendelscherm voor werk"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Sluiten"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index f1b69b4a9695..4ac1f8486768 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"କ୍ୱିକ୍ ସେଟିଂସ୍।"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"କୁଇକ ସେଟିଂସ ଏବଂ ବିଜ୍ଞପ୍ତି ସେଡ।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ୱର୍କ ଲକ୍ ସ୍କ୍ରୀନ୍"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ବନ୍ଦ କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 0c7708fe2e05..236093010eea 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸੂਚਨਾ ਸ਼ੇਡ।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">" ਲਾਕ ਸਕ੍ਰੀਨ।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ਕਾਰਜ-ਸਥਾਨ ਲਾਕ ਸਕ੍ਰੀਨ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ਬੰਦ ਕਰੋ"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ਬੰਦ ਕਰੋ"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ਕੈਮਰਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੈ"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ਧਿਆਨ ਸੁਵਿਧਾ ਨੂੰ ਚਾਲੂ ਹੈ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 611e996b806d..18450ab36f63 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obszar powiadomień."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Szybkie ustawienia."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Szybkie ustawienia i obszar powiadomień."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekran blokady."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekran blokady wyświetlany podczas działania"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zamknij"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Przełącz na profil służbowy"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zamknij"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Ustawienia ekranu blokady"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Sieć Wi-Fi jest niedostępna"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tryb priorytetowy jest włączony"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asystent jest aktywny"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 105031c22503..8add565ce87d 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configurações rápidas e aba de notificações."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Tela de bloqueio de trabalho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 8145483c2933..f8a684c626e2 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Painel de notificações."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Definições rápidas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Definições rápidas e painel de notificações."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecrã de bloqueio."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ecrã de bloqueio de trabalho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 105031c22503..8add565ce87d 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configurações rápidas e aba de notificações."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Tela de bloqueio de trabalho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 0303e646c237..a4698d600582 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Fereastră pentru notificări."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setări rapide."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Fereastră de Setări rapide și notificări."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecranul de blocare."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ecran de blocare pentru serviciu"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Închide"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 9a71eea4bd4c..32a784c94b8c 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель уведомлений"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Быстрые настройки"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Быстрые настройки и панель уведомлений."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блокировки."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Заблокировано"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыть"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index ba04fabf1878..8bb334ee1d43 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"දැනුම්දීම් ආවරණය."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ක්ෂණික සැකසීම්."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ඉක්මන් සැකසීම් සහ දැනුම්දීම් ඡායිතය."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"අගුළු තිරය."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"කාර්යාල අගුලු තිරය"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"වසන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 36058de155d9..f4181540e7fb 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel upozornení."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rýchle nastavenia."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Rýchle nastavenia a panel upozornení"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Uzamknutá obrazovka"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Uzamknutá obrazovka pracovného profilu"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zavrieť"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index f4ae067e50dc..3bc835165fde 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon z obvestili."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hitre nastavitve."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hitre nastavitve in zaslon z obvestili"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaklenjen zaslon"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Zaklenjen zaslon delovnega profila"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zapri"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index f69221a8f3ca..6a35e38ee9b3 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Streha e njoftimeve."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cilësimet e shpejta."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"\"Cilësimet e shpejta\" dhe \"Streha e njoftimeve\"."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekrani i kyçjes."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekrani i kyçjes së punës"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Mbylle"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 19e59523611d..8dcf0cd3a6bc 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meddelandepanel."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snabbinställningar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Snabbinställningar och meddelandepanel."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låsskärm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låsskärm för arbete"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Stäng"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 1cfa514f1b91..49d4733c8b3c 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kivuli cha arifa."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mipangilio ya haraka."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Mipangilio ya haraka na Sehemu ya arifa."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Skrini iliyofungwa."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrini iliyofungwa ya kazini"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Funga"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tumia wasifu wa kazini"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Funga"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Mipangilio ya skrini iliyofungwa"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi haipatikani"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Hali ya kipaumbele imewashwa"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Programu ya Mratibu imewashwa"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index a29df5914a3a..4a0cb46cb52d 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"నోటిఫికేషన్ షేడ్."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"శీఘ్ర సెట్టింగ్లు."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"క్విక్ సెట్టింగ్లు, నోటిఫికేషన్ తెర."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"లాక్ స్క్రీన్."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"కార్యాలయ లాక్ స్క్రీన్"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"మూసివేస్తుంది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index f0a2123a546a..64a528066931 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1110,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"สลับไปใช้โปรไฟล์งาน"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ปิด"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"การตั้งค่าหน้าจอล็อก"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ไม่พร้อมใช้งาน"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"กล้องถูกบล็อกอยู่"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"กล้องและไมโครโฟนถูกบล็อกอยู่"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ไมโครโฟนถูกบล็อกอยู่"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"โหมดลำดับความสำคัญเปิดอยู่"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"การเรียกใช้งาน Assistant เปิดอยู่"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 05f4628e57c1..d4d583f105e0 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mga mabilisang setting."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Mga mabilisang setting at Notification shade."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Lock screen sa trabaho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Isara"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 81f84860a3bb..4df50fc99c6d 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildirim gölgesi."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hızlı ayarlar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hızlı ayarlar ve Bildirim gölgesi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilit ekranı"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"İş profili kilit ekranı"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Kapat"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 3ba43d571902..c24f858e1154 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель сповіщень."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Швидке налаштування."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Швидкі налаштування й панель сповіщень."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заблокований екран."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Екран блокування завдання"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Закрити"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в робочий профіль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрити"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Параметри заблокованого екрана"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Мережа Wi-Fi недоступна"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камеру заблоковано"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камеру й мікрофон заблоковано"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрофон заблоковано"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим пріоритету ввімкнено"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Асистента активовано"</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 5388be5f72fa..17ff36b09f63 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"اطلاعاتی شیڈ۔"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"فوری ترتیبات۔"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"فوری ترتیبات اور اطلاعاتی شیڈ۔"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"مقفل اسکرین۔"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"دفتری مقفل اسکرین"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"بند کریں"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index d97be0684e57..0b488f8fb0cd 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bóng thông báo."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cài đặt nhanh."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Cài đặt nhanh và ngăn thông báo."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Màn hình khóa."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Màn hình khóa công việc"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Đóng"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Chuyển sang hồ sơ công việc"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Đóng"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Cài đặt màn hình khoá"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Không có Wi-Fi"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bị chặn"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bị chặn"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Chế độ ưu tiên đang bật"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Trợ lý đang bật"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index ea1c94ad96d6..b5d0e01d1c91 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知栏。"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷设置。"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快捷设置和通知栏。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"锁定屏幕。"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"工作锁定屏幕"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"关闭"</string> @@ -1019,7 +1018,7 @@ <string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string> <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> <string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string> - <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"暂时已连接"</string> + <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暂时连接"</string> <string name="mobile_data_poor_connection" msgid="819617772268371434">"连接状况不佳"</string> <string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string> <string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index cfd1cc8470a6..cacf20530642 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快速設定。"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快速設定和通知欄。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"上鎖畫面。"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"工作螢幕鎖定"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 450a3cca66c2..3fbdd487534d 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷設定。"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快速設定和通知欄。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"螢幕鎖定。"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Work 螢幕鎖定"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 85854c55d696..8039ca14ad3a 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -198,8 +198,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Umthunzi wesaziso."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Izilingiselelo ezisheshayo."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Amasethingi asheshayo Nomthunzi wezaziso."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Khiya isikrini."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ukukhiya isikrini somsebenzi"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Vala"</string> @@ -1111,16 +1110,10 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Shintshela kuphrofayela yomsebenzi"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Vala"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Amasethingi okukhiya isikrini"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> - <!-- no translation found for assistant_attention_content_description (6830215897604642875) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"I-Wi-Fi ayitholakali"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Imodi ebalulekile ivuliwe"</string> + <string name="assistant_attention_content_description" msgid="6830215897604642875">"Ukunaka kwe-Assistant kuvuliwe"</string> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index c6cc0bc01116..d4ebd100a91d 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -163,8 +163,8 @@ <color name="magnification_border_color">#F29900</color> <color name="magnification_switch_button_color">#7F000000</color> <color name="magnification_drag_corner_background">#E5FFFFFF</color> - <color name="magnification_drag_handle_color">#B3000000</color> - <color name="magnification_drag_handle_tint">#111111</color> + <color name="magnification_drag_handle_stroke">#000000</color> + <color name="magnification_drag_handle_background_change">#111111</color> <color name="accessibility_magnifier_bg">#FCFCFC</color> <color name="accessibility_magnifier_bg_stroke">#E0E0E0</color> <color name="accessibility_magnifier_icon_color">#252525</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 738cfd7c95bf..e65c327736e1 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -500,8 +500,8 @@ space --> <bool name="config_showBatteryEstimateQSBH">false</bool> - <!-- Whether to show a severe low battery dialog. --> - <bool name="config_severe_battery_dialog">false</bool> + <!-- Whether to show extra battery saver confirmation dialog. --> + <bool name="config_extra_battery_saver_confirmation">false</bool> <!-- A path representing a shield. Will sometimes be displayed with the battery icon when needed. This path is a 10px wide and 13px tall. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 897271588655..aba3fc4615c9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -573,7 +573,7 @@ <dimen name="qs_tile_margin_horizontal">8dp</dimen> <dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen> <dimen name="qs_tile_margin_top_bottom">4dp</dimen> - <dimen name="qs_brightness_margin_top">12dp</dimen> + <dimen name="qs_brightness_margin_top">8dp</dimen> <dimen name="qs_brightness_margin_bottom">16dp</dimen> <dimen name="qqs_layout_margin_top">16dp</dimen> <dimen name="qqs_layout_padding_bottom">24dp</dimen> @@ -625,7 +625,7 @@ <dimen name="qs_header_row_min_height">48dp</dimen> <dimen name="qs_header_non_clickable_element_height">24dp</dimen> - <dimen name="new_qs_header_non_clickable_element_height">20dp</dimen> + <dimen name="new_qs_header_non_clickable_element_height">24dp</dimen> <dimen name="qs_footer_padding">20dp</dimen> <dimen name="qs_security_footer_height">88dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a988813a96d3..f4b3b87aab16 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -407,12 +407,6 @@ <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication --> <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string> - <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> - <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string> - <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> - <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string> - <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> - <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string> <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] --> <string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string> <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] --> @@ -2343,6 +2337,8 @@ <string name="magnification_mode_switch_state_window">Magnify part of screen</string> <!-- Click action label for magnification switch. [CHAR LIMIT=NONE] --> <string name="magnification_mode_switch_click_label">Switch</string> + <!-- Click action label for magnification settings panel. [CHAR LIMIT=NONE] --> + <string name="magnification_open_settings_click_label">Open magnification settings</string> <!-- Label of the corner of a rectangle that you can tap and drag to resize the magnification area. [CHAR LIMIT=NONE] --> <string name="magnification_drag_corner_to_resize">Drag corner to resize</string> @@ -2364,6 +2360,8 @@ <!-- Description of the window magnification Bottom handle [CHAR LIMIT=NONE]--> <string name="accessibility_magnification_bottom_handle">Bottom handle</string> + <!-- Description of the window magnification panel [CHAR LIMIT=NONE]--> + <string name="accessibility_magnification_settings_panel_description">Magnification settings</string> <!-- Title of the window magnification panel option Magnifier size [CHAR LIMIT=NONE]--> <string name="accessibility_magnifier_size">Magnifier size</string> <!-- Title of the window magnification panel option Zoom [CHAR LIMIT=NONE]--> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 6dd359cb6351..45a5ce34f830 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -18,7 +18,6 @@ package com.android.systemui.shared.system; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; -import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.app.ActivityTaskManager.getService; import android.annotation.NonNull; @@ -45,6 +44,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.provider.Settings; import android.util.Log; +import android.view.Display; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; @@ -112,6 +112,13 @@ public class ActivityManagerWrapper { } /** + * @see #getRunningTasks(boolean , int) + */ + public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) { + return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY); + } + + /** * We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen, * we'll get back 2 activities for each split app and one for launcher. Launcher might be more * "recently" used than one of the split apps so if we only request 2 tasks, then we might miss @@ -120,10 +127,12 @@ public class ActivityManagerWrapper { * @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks * filtering only for tasks that can be visible in the recent tasks list. */ - public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) { + public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents, + int displayId) { // Note: The set of running tasks from the system is ordered by recency List<ActivityManager.RunningTaskInfo> tasks = - mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents); + mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, + filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId); return tasks.toArray(new RunningTaskInfo[tasks.size()]); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java index ae6861812b4c..44f9d43f5470 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java @@ -16,30 +16,9 @@ package com.android.systemui.shared.system; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.view.RemoteAnimationTarget.MODE_CHANGING; -import static android.view.RemoteAnimationTarget.MODE_CLOSING; -import static android.view.RemoteAnimationTarget.MODE_OPENING; -import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; -import static android.view.WindowManager.TRANSIT_OPEN; -import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; -import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; -import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; - -import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.app.ActivityManager; -import android.app.WindowConfiguration; -import android.graphics.Rect; import android.util.ArrayMap; -import android.util.SparseBooleanArray; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; -import android.view.WindowManager; import android.window.TransitionInfo; import android.window.TransitionInfo.Change; @@ -53,156 +32,6 @@ import java.util.function.Predicate; */ public class RemoteAnimationTargetCompat { - private static int newModeToLegacyMode(int newMode) { - switch (newMode) { - case WindowManager.TRANSIT_OPEN: - case WindowManager.TRANSIT_TO_FRONT: - return MODE_OPENING; - case WindowManager.TRANSIT_CLOSE: - case WindowManager.TRANSIT_TO_BACK: - return MODE_CLOSING; - default: - return MODE_CHANGING; - } - } - - /** - * Almost a copy of Transitions#setupStartState. - * TODO: remove when there is proper cross-process transaction sync. - */ - @SuppressLint("NewApi") - private static void setupLeash(@NonNull SurfaceControl leash, - @NonNull TransitionInfo.Change change, int layer, - @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { - final boolean isOpening = TransitionUtil.isOpeningType(info.getType()); - // Put animating stuff above this line and put static stuff below it. - int zSplitLine = info.getChanges().size(); - // changes should be ordered top-to-bottom in z - final int mode = change.getMode(); - - t.reparent(leash, info.getRootLeash()); - final Rect absBounds = - (mode == TRANSIT_OPEN) ? change.getEndAbsBounds() : change.getStartAbsBounds(); - t.setPosition(leash, absBounds.left - info.getRootOffset().x, - absBounds.top - info.getRootOffset().y); - - // Put all the OPEN/SHOW on top - if (TransitionUtil.isOpeningType(mode)) { - if (isOpening) { - t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); - if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) { - // if transferred, it should be left visible. - t.setAlpha(leash, 0.f); - } - } else { - // put on bottom and leave it visible - t.setLayer(leash, zSplitLine - layer); - } - } else if (TransitionUtil.isClosingType(mode)) { - if (isOpening) { - // put on bottom and leave visible - t.setLayer(leash, zSplitLine - layer); - } else { - // put on top - t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); - } - } else { // CHANGE - t.setLayer(leash, zSplitLine + info.getChanges().size() - layer); - } - } - - @SuppressLint("NewApi") - private static SurfaceControl createLeash(TransitionInfo info, TransitionInfo.Change change, - int order, SurfaceControl.Transaction t) { - // TODO: once we can properly sync transactions across process, then get rid of this leash. - if (change.getParent() != null && (change.getFlags() & FLAG_IS_WALLPAPER) != 0) { - // Special case for wallpaper atm. Normally these are left alone; but, a quirk of - // making leashes means we have to handle them specially. - return change.getLeash(); - } - SurfaceControl leashSurface = new SurfaceControl.Builder() - .setName(change.getLeash().toString() + "_transition-leash") - .setContainerLayer() - // Initial the surface visible to respect the visibility of the original surface. - .setHidden(false) - .setParent(info.getRootLeash()) - .build(); - // Copied Transitions setup code (which expects bottom-to-top order, so we swap here) - setupLeash(leashSurface, change, info.getChanges().size() - order, info, t); - t.reparent(change.getLeash(), leashSurface); - t.setAlpha(change.getLeash(), 1.0f); - t.show(change.getLeash()); - t.setPosition(change.getLeash(), 0, 0); - t.setLayer(change.getLeash(), 0); - return leashSurface; - } - - /** - * Creates a new RemoteAnimationTarget from the provided change info - */ - public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order, - TransitionInfo info, SurfaceControl.Transaction t, - @Nullable ArrayMap<SurfaceControl, SurfaceControl> leashMap) { - final SurfaceControl leash = createLeash(info, change, order, t); - if (leashMap != null) { - leashMap.put(change.getLeash(), leash); - } - return newTarget(change, order, leash); - } - - /** - * Creates a new RemoteAnimationTarget from the provided change and leash - */ - public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order, - SurfaceControl leash) { - int taskId; - boolean isNotInRecents; - ActivityManager.RunningTaskInfo taskInfo; - WindowConfiguration windowConfiguration; - - taskInfo = change.getTaskInfo(); - if (taskInfo != null) { - taskId = taskInfo.taskId; - isNotInRecents = !taskInfo.isRunning; - windowConfiguration = taskInfo.configuration.windowConfiguration; - } else { - taskId = INVALID_TASK_ID; - isNotInRecents = true; - windowConfiguration = new WindowConfiguration(); - } - - Rect localBounds = new Rect(change.getEndAbsBounds()); - localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y); - - RemoteAnimationTarget target = new RemoteAnimationTarget( - taskId, - newModeToLegacyMode(change.getMode()), - // TODO: once we can properly sync transactions across process, - // then get rid of this leash. - leash, - (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0, - null, - // TODO(shell-transitions): we need to send content insets? evaluate how its used. - new Rect(0, 0, 0, 0), - order, - null, - localBounds, - new Rect(change.getEndAbsBounds()), - windowConfiguration, - isNotInRecents, - null, - new Rect(change.getStartAbsBounds()), - taskInfo, - change.getAllowEnterPip(), - (change.getFlags() & FLAG_IS_DIVIDER_BAR) != 0 - ? TYPE_DOCK_DIVIDER : INVALID_WINDOW_TYPE - ); - target.setWillShowImeOnTarget( - (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0); - target.setRotationChange(change.getEndRotation() - change.getStartRotation()); - return target; - } - /** * Represents a TransitionInfo object as an array of old-style app targets * @@ -211,7 +40,7 @@ public class RemoteAnimationTargetCompat { */ public static RemoteAnimationTarget[] wrapApps(TransitionInfo info, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { - return wrap(info, t, leashMap, new LeafTaskFilter()); + return wrap(info, t, leashMap, new TransitionUtil.LeafTaskFilter()); } /** @@ -224,8 +53,8 @@ public class RemoteAnimationTargetCompat { */ public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers, SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) { - return wrap(info, t, leashMap, (change) -> - (wallpapers ? isWallpaper(change) : isNonApp(change))); + return wrap(info, t, leashMap, (change) -> (wallpapers + ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change))); } private static RemoteAnimationTarget[] wrap(TransitionInfo info, @@ -235,45 +64,10 @@ public class RemoteAnimationTargetCompat { for (int i = 0; i < info.getChanges().size(); i++) { TransitionInfo.Change change = info.getChanges().get(i); if (filter.test(change)) { - out.add(newTarget(change, info.getChanges().size() - i, info, t, leashMap)); + out.add(TransitionUtil.newTarget( + change, info.getChanges().size() - i, info, t, leashMap)); } } return out.toArray(new RemoteAnimationTarget[out.size()]); } - - /** Returns `true` if `change` is a wallpaper. */ - public static boolean isWallpaper(Change change) { - return (change.getTaskInfo() == null) - && change.hasFlags(FLAG_IS_WALLPAPER) - && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY); - } - - /** Returns `true` if `change` is not an app window or wallpaper. */ - public static boolean isNonApp(Change change) { - return (change.getTaskInfo() == null) - && !change.hasFlags(FLAG_IS_WALLPAPER) - && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY); - } - - /** - * Filter that selects leaf-tasks only. THIS IS ORDER-DEPENDENT! For it to work properly, you - * MUST call `test` in the same order that the changes appear in the TransitionInfo. - */ - public static class LeafTaskFilter implements Predicate<Change> { - private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray(); - - @Override - public boolean test(Change change) { - final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); - // Children always come before parent since changes are in top-to-bottom z-order. - if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) { - // has children, so not a leaf. Skip. - return false; - } - if (taskInfo.hasParentTask()) { - mChildTaskTargets.put(taskInfo.parentTaskId, true); - } - return true; - } - } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index 70a36ce7e904..6f7d66d03cab 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -20,8 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; - -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.newTarget; +import static android.view.WindowManager.TRANSIT_SLEEP; import android.annotation.SuppressLint; import android.app.ActivityManager; @@ -45,10 +44,10 @@ import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.wm.shell.util.TransitionUtil; import java.util.ArrayList; +import java.util.HashMap; /** * Helper class to build {@link RemoteTransition} objects @@ -58,7 +57,7 @@ public class RemoteTransitionCompat { /** Constructor specifically for recents animation */ public static RemoteTransition newRemoteTransition(RecentsAnimationListener recents, - RecentsAnimationControllerCompat controller, IApplicationThread appThread) { + IApplicationThread appThread) { IRemoteTransition remote = new IRemoteTransition.Stub() { final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap(); IBinder mToken = null; @@ -69,7 +68,7 @@ public class RemoteTransitionCompat { IRemoteTransitionFinishedCallback finishedCallback) { // TODO(b/177438007): Move this set-up logic into launcher's animation impl. mToken = transition; - mRecentsSession.start(controller, recents, mToken, info, t, finishedCallback); + mRecentsSession.start(recents, mToken, info, t, finishedCallback); } @Override @@ -98,9 +97,8 @@ public class RemoteTransitionCompat { * TODO(b/177438007): Remove this once Launcher handles shell transitions directly. */ @VisibleForTesting - static class RecentsControllerWrap extends RecentsAnimationControllerCompat { + static class RecentsControllerWrap extends IRecentsAnimationController.Default { private RecentsAnimationListener mListener = null; - private RecentsAnimationControllerCompat mWrapped = null; private IRemoteTransitionFinishedCallback mFinishCB = null; /** @@ -137,7 +135,7 @@ public class RemoteTransitionCompat { /** The latest state that the recents animation is operating in. */ private int mState = STATE_NORMAL; - void start(RecentsAnimationControllerCompat wrapped, RecentsAnimationListener listener, + void start(RecentsAnimationListener listener, IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishedCallback) { if (mInfo != null) { @@ -145,7 +143,6 @@ public class RemoteTransitionCompat { + " recents is already active."); } mListener = listener; - mWrapped = wrapped; mInfo = info; mFinishCB = finishedCallback; mPausingTasks = new ArrayList<>(); @@ -160,16 +157,15 @@ public class RemoteTransitionCompat { final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>(); final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>(); - RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = - new RemoteAnimationTargetCompat.LeafTaskFilter(); + TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter(); // About layering: we divide up the "layer space" into 3 regions (each the size of // the change count). This lets us categorize things into above/below/between // while maintaining their relative ordering. for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); - if (RemoteAnimationTargetCompat.isWallpaper(change)) { - final RemoteAnimationTarget target = newTarget(change, + if (TransitionUtil.isWallpaper(change)) { + final RemoteAnimationTarget target = TransitionUtil.newTarget(change, // wallpapers go into the "below" layer space info.getChanges().size() - i, info, t, mLeashMap); wallpapers.add(target); @@ -177,7 +173,7 @@ public class RemoteTransitionCompat { t.setAlpha(target.leash, 1); } else if (leafTaskFilter.test(change)) { // start by putting everything into the "below" layer space. - final RemoteAnimationTarget target = newTarget(change, + final RemoteAnimationTarget target = TransitionUtil.newTarget(change, info.getChanges().size() - i, info, t, mLeashMap); apps.add(target); if (TransitionUtil.isClosingType(change.getMode())) { @@ -203,13 +199,20 @@ public class RemoteTransitionCompat { } } t.apply(); - mListener.onAnimationStart(this, apps.toArray(new RemoteAnimationTarget[apps.size()]), + mListener.onAnimationStart(new RecentsAnimationControllerCompat(this), + apps.toArray(new RemoteAnimationTarget[apps.size()]), wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]), new Rect(0, 0, 0, 0), new Rect()); } @SuppressLint("NewApi") boolean merge(TransitionInfo info, SurfaceControl.Transaction t) { + if (info.getType() == TRANSIT_SLEEP) { + // A sleep event means we need to stop animations immediately, so cancel here. + mListener.onAnimationCanceled(new HashMap<>()); + finish(mWillFinishToHome, false /* userLeaveHint */); + return false; + } ArrayList<TransitionInfo.Change> openingTasks = null; ArrayList<TransitionInfo.Change> closingTasks = null; mAppearedTargets = null; @@ -217,8 +220,8 @@ public class RemoteTransitionCompat { TransitionInfo.Change recentsOpening = null; boolean foundRecentsClosing = false; boolean hasChangingApp = false; - final RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = - new RemoteAnimationTargetCompat.LeafTaskFilter(); + final TransitionUtil.LeafTaskFilter leafTaskFilter = + new TransitionUtil.LeafTaskFilter(); for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); @@ -246,6 +249,13 @@ public class RemoteTransitionCompat { closingTasks.add(change); } } else if (change.getMode() == TRANSIT_CHANGE) { + // Finish recents animation if the display is changed, so the default + // transition handler can play the animation such as rotation effect. + if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) { + mListener.onSwitchToScreenshot(() -> finish(false /* toHome */, + false /* userLeaveHint */)); + return false; + } hasChangingApp = true; } } @@ -301,7 +311,8 @@ public class RemoteTransitionCompat { int pausingIdx = TaskState.indexOf(mPausingTasks, change); if (pausingIdx >= 0) { // Something is showing/opening a previously-pausing app. - targets[i] = newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash); + targets[i] = TransitionUtil.newTarget(change, layer, + mPausingTasks.get(pausingIdx).mLeash); mOpeningTasks.add(mPausingTasks.remove(pausingIdx)); // Setup hides opening tasks initially, so make it visible again (since we // are already showing it). @@ -309,7 +320,7 @@ public class RemoteTransitionCompat { t.setAlpha(change.getLeash(), 1.f); } else { // We are receiving new opening tasks, so convert to onTasksAppeared. - targets[i] = newTarget(change, layer, info, t, mLeashMap); + targets[i] = TransitionUtil.newTarget(change, layer, info, t, mLeashMap); t.reparent(targets[i].leash, mInfo.getRootLeash()); t.setLayer(targets[i].leash, layer); mOpeningTasks.add(new TaskState(change, targets[i].leash)); @@ -337,13 +348,9 @@ public class RemoteTransitionCompat { } } - @Override public ThumbnailData screenshotTask(int taskId) { + @Override public TaskSnapshot screenshotTask(int taskId) { try { - final TaskSnapshot snapshot = - ActivityTaskManager.getService().takeTaskSnapshot(taskId); - if (snapshot != null) { - return new ThumbnailData(snapshot); - } + return ActivityTaskManager.getService().takeTaskSnapshot(taskId); } catch (RemoteException e) { Log.e(TAG, "Failed to screenshot task", e); } @@ -351,30 +358,24 @@ public class RemoteTransitionCompat { } @Override public void setInputConsumerEnabled(boolean enabled) { - if (enabled) { - // transient launches don't receive focus automatically. Since we are taking over - // the gesture now, take focus explicitly. - // This also moves recents back to top if the user gestured before a switch - // animation finished. - try { - ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId); - } catch (RemoteException e) { - Log.e(TAG, "Failed to set focused task", e); - } + if (!enabled) return; + // transient launches don't receive focus automatically. Since we are taking over + // the gesture now, take focus explicitly. + // This also moves recents back to top if the user gestured before a switch + // animation finished. + try { + ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId); + } catch (RemoteException e) { + Log.e(TAG, "Failed to set focused task", e); } - if (mWrapped != null) mWrapped.setInputConsumerEnabled(enabled); } @Override public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { - if (mWrapped != null) mWrapped.setAnimationTargetsBehindSystemBars(behindSystemBars); } @Override public void setFinishTaskTransaction(int taskId, PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) { mPipTransaction = finishTransaction; - if (mWrapped != null) { - mWrapped.setFinishTaskTransaction(taskId, finishTransaction, overlay); - } } @Override @@ -384,7 +385,6 @@ public class RemoteTransitionCompat { Log.e(TAG, "Duplicate call to finish", new RuntimeException()); return; } - if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint); final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); final WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -457,7 +457,6 @@ public class RemoteTransitionCompat { // for releasing the leashes created by local. mInfo.releaseAllSurfaces(); // Reset all members. - mWrapped = null; mListener = null; mFinishCB = null; mPausingTasks = null; @@ -471,23 +470,20 @@ public class RemoteTransitionCompat { } @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { - if (mWrapped != null) mWrapped.setDeferCancelUntilNextTransition(defer, screenshot); } @Override public void cleanupScreenshot() { - if (mWrapped != null) mWrapped.cleanupScreenshot(); } @Override public void setWillFinishToHome(boolean willFinishToHome) { mWillFinishToHome = willFinishToHome; - if (mWrapped != null) mWrapped.setWillFinishToHome(willFinishToHome); } /** * @see IRecentsAnimationController#removeTask */ @Override public boolean removeTask(int taskId) { - return mWrapped != null ? mWrapped.removeTask(taskId) : false; + return false; } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt index fe8b8c944d13..c98e9b40e7ab 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt @@ -40,7 +40,7 @@ data class KeyguardFaceListenModel( var keyguardGoingAway: Boolean = false, var listeningForFaceAssistant: Boolean = false, var occludingAppRequestingFaceAuth: Boolean = false, - val postureAllowsListening: Boolean = false, + var postureAllowsListening: Boolean = false, var primaryUser: Boolean = false, var secureCameraLaunched: Boolean = false, var supportsDetect: Boolean = false, @@ -70,6 +70,7 @@ data class KeyguardFaceListenModel( listeningForFaceAssistant.toString(), occludingAppRequestingFaceAuth.toString(), primaryUser.toString(), + postureAllowsListening.toString(), secureCameraLaunched.toString(), supportsDetect.toString(), switchingUser.toString(), @@ -109,6 +110,7 @@ data class KeyguardFaceListenModel( listeningForFaceAssistant = model.listeningForFaceAssistant occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth primaryUser = model.primaryUser + postureAllowsListening = model.postureAllowsListening secureCameraLaunched = model.secureCameraLaunched supportsDetect = model.supportsDetect switchingUser = model.switchingUser @@ -152,6 +154,7 @@ data class KeyguardFaceListenModel( "listeningForFaceAssistant", "occludingAppRequestingFaceAuth", "primaryUser", + "postureAllowsListening", "secureCameraLaunched", "supportsDetect", "switchingUser", diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index c1fae9e44bd3..33bea027cd20 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -69,6 +69,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { private Interpolator mLinearOutSlowInInterpolator; private Interpolator mFastOutLinearInInterpolator; + private DisappearAnimationListener mDisappearAnimationListener; public KeyguardPasswordView(Context context) { this(context, null); @@ -186,9 +187,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { return; } Insets shownInsets = controller.getShownStateInsets(); - Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, - (int) (-shownInsets.bottom / 4 - * anim.getAnimatedFraction()))); + int dist = (int) (-shownInsets.bottom / 4 + * anim.getAnimatedFraction()); + Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist)); + if (mDisappearAnimationListener != null) { + mDisappearAnimationListener.setTranslationY(-dist); + } + controller.setInsetsAndAlpha(insets, (float) animation.getAnimatedValue(), anim.getAnimatedFraction()); @@ -209,6 +214,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { controller.finish(false); runOnFinishImeAnimationRunnable(); finishRunnable.run(); + mDisappearAnimationListener = null; Trace.endSection(); }); } @@ -286,4 +292,19 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { } }); } + + /** + * Listens to the progress of the disappear animation and handles it. + */ + interface DisappearAnimationListener { + void setTranslationY(int transY); + } + + /** + * Set an instance of the disappear animation listener to this class. This will be + * removed when the animation completes. + */ + public void setDisappearAnimationListener(DisappearAnimationListener listener) { + mDisappearAnimationListener = listener; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index c6f0eeed108f..66d5d097ab04 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -173,6 +173,17 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private @Mode int mCurrentMode = MODE_UNINITIALIZED; private int mWidth = -1; + /** + * This callback is used to animate KeyguardSecurityContainer and its child views based on + * the interaction with the ime. After + * {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)}, + * {@link #onApplyWindowInsets} is called where we + * set the bottom padding to be the height of the keyboard. We use this padding to determine + * the delta of vertical distance for y-translation animations. + * Note that bottom padding is not set when the disappear animation is started because + * we are deferring the y translation logic to the animator in + * {@link KeyguardPasswordView#startDisappearAnimation(Runnable)} + */ private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @@ -213,7 +224,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout { continue; } interpolatedFraction = animation.getInterpolatedFraction(); - final int paddingBottom = (int) MathUtils.lerp( start, end, interpolatedFraction); @@ -568,13 +578,21 @@ public class KeyguardSecurityContainer extends ConstraintLayout { */ public void startDisappearAnimation(SecurityMode securitySelection) { mDisappearAnimRunning = true; - mViewMode.startDisappearAnimation(securitySelection); + if (securitySelection == SecurityMode.Password + && mSecurityViewFlipper.getSecurityView() instanceof KeyguardPasswordView) { + ((KeyguardPasswordView) mSecurityViewFlipper.getSecurityView()) + .setDisappearAnimationListener(this::setTranslationY); + } else { + mViewMode.startDisappearAnimation(securitySelection); + } } /** * This will run when the bouncer shows in all cases except when the user drags the bouncer up. */ public void startAppearAnimation(SecurityMode securityMode) { + setTranslationY(0f); + setAlpha(1f); updateChildren(0 /* translationY */, 1f /* alpha */); mViewMode.startAppearAnimation(securityMode); } @@ -623,7 +641,13 @@ public class KeyguardSecurityContainer extends ConstraintLayout { int inset = max(bottomInset, imeInset); int paddingBottom = max(inset, getContext().getResources() .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin)); - setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom); + // If security mode is password, we rely on the animation value of defined in + // KeyguardPasswordView to determine the y translation animation. + // This means that we will prevent the WindowInsetsAnimationCallback from setting any y + // translation values by preventing the setting of the padding here. + if (!mDisappearAnimRunning) { + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom); + } return insets.inset(0, 0, 0, inset); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a4ec8e1b72f2..30e2a0b613ee 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -160,6 +160,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.DevicePostureController; +import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt; import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.Assert; import com.android.systemui.util.settings.SecureSettings; @@ -368,7 +369,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final FaceManager mFaceManager; private final LockPatternUtils mLockPatternUtils; @VisibleForTesting - @DevicePostureController.DevicePostureInt + @DevicePostureInt protected int mConfigFaceAuthSupportedPosture; private KeyguardBypassController mKeyguardBypassController; @@ -685,7 +686,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab public void onTrustManagedChanged(boolean managed, int userId) { Assert.isMainThread(); mUserTrustIsManaged.put(userId, managed); - mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); + boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId); + mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId), + trustUsuallyManaged, "onTrustManagedChanged"); + mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -873,7 +877,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) { mBackgroundExecutor.execute( - () -> mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId)); + () -> { + mLogger.logReportSuccessfulBiometricUnlock(isStrongBiometric, userId); + mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId); + }); } private void handleFingerprintAuthFailed() { @@ -1859,10 +1866,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final DevicePostureController.Callback mPostureCallback = new DevicePostureController.Callback() { @Override - public void onPostureChanged(int posture) { + public void onPostureChanged(@DevicePostureInt int posture) { + boolean currentPostureAllowsFaceAuth = doesPostureAllowFaceAuth(mPostureState); + boolean newPostureAllowsFaceAuth = doesPostureAllowFaceAuth(posture); mPostureState = posture; - updateFaceListeningState(BIOMETRIC_ACTION_UPDATE, - FACE_AUTH_UPDATED_POSTURE_CHANGED); + if (currentPostureAllowsFaceAuth && !newPostureAllowsFaceAuth) { + mLogger.d("New posture does not allow face auth, stopping it"); + updateFaceListeningState(BIOMETRIC_ACTION_STOP, + FACE_AUTH_UPDATED_POSTURE_CHANGED); + } } }; @@ -2393,8 +2405,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab updateSecondaryLockscreenRequirement(user); List<UserInfo> allUsers = mUserManager.getUsers(); for (UserInfo userInfo : allUsers) { + boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userInfo.id); + mLogger.logTrustUsuallyManagedUpdated(userInfo.id, + mUserTrustIsUsuallyManaged.get(userInfo.id), + trustUsuallyManaged, "init from constructor"); mUserTrustIsUsuallyManaged.put(userInfo.id, - mTrustManager.isTrustUsuallyManaged(userInfo.id)); + trustUsuallyManaged); } updateAirplaneModeState(); @@ -2434,9 +2450,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void updateFaceEnrolled(int userId) { - mIsFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty() + Boolean isFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty() && mBiometricEnabledForUser.get(userId) && mAuthController.isFaceAuthEnrolled(userId); + mIsFaceEnrolled = isFaceEnrolled; + mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled); } public boolean isFaceSupported() { @@ -2515,11 +2533,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // If this message exists, we should not authenticate again until this message is // consumed by the handler if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) { + mLogger.logHandlerHasAuthContinueMsgs(action); return; } // don't start running fingerprint until they're registered if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) { + mLogger.d("All FP authenticators not registered, skipping FP listening state update"); return; } final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported()); @@ -2892,9 +2912,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user); final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant(); final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown(); - final boolean isPostureAllowedForFaceAuth = - mConfigFaceAuthSupportedPosture == 0 /* DEVICE_POSTURE_UNKNOWN */ ? true - : (mPostureState == mConfigFaceAuthSupportedPosture); + final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState); // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware. final boolean shouldListen = @@ -2943,6 +2961,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return shouldListen; } + private boolean doesPostureAllowFaceAuth(@DevicePostureInt int posture) { + return mConfigFaceAuthSupportedPosture == DEVICE_POSTURE_UNKNOWN + || (posture == mConfigFaceAuthSupportedPosture); + } + private void logListenerModelData(@NonNull KeyguardListenModel model) { mLogger.logKeyguardListenerModel(model); if (model instanceof KeyguardFingerprintListenModel) { @@ -3103,9 +3126,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @VisibleForTesting boolean isUnlockWithFingerprintPossible(int userId) { // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once. - mIsUnlockWithFingerprintPossible.put(userId, mFpm != null + boolean fpEnrolled = mFpm != null && !mFingerprintSensorProperties.isEmpty() - && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId)); + && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId); + mLogger.logFpEnrolledUpdated(userId, + mIsUnlockWithFingerprintPossible.getOrDefault(userId, false), + fpEnrolled); + mIsUnlockWithFingerprintPossible.put(userId, fpEnrolled); return mIsUnlockWithFingerprintPossible.get(userId); } @@ -3221,7 +3248,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab void handleUserSwitching(int userId, CountDownLatch latch) { Assert.isMainThread(); clearBiometricRecognized(); - mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); + boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId); + mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId), + trustUsuallyManaged, "userSwitching"); + mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt index bc0bd8c53d26..20f90072161b 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt @@ -16,6 +16,7 @@ package com.android.keyguard.logging +import android.hardware.biometrics.BiometricSourceType import com.android.systemui.dagger.SysUISingleton import com.android.systemui.log.dagger.BiometricLog import com.android.systemui.plugins.log.LogBuffer @@ -157,6 +158,36 @@ class BiometricUnlockLogger @Inject constructor(@BiometricLog private val logBuf } ) } + + fun deferringAuthenticationDueToSleep( + userId: Int, + biometricSourceType: BiometricSourceType, + alreadyPendingAuth: Boolean + ) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + str1 = biometricSourceType.name + bool2 = alreadyPendingAuth + }, + { + "onBiometricAuthenticated, deferring auth: userId: $int1, " + + "biometricSourceType: $str1, " + + "goingToSleep: true, " + + "mPendingAuthentication != null: $bool2" + } + ) + } + + fun finishedGoingToSleepWithPendingAuth() { + logBuffer.log( + TAG, + LogLevel.DEBUG, + "onFinishedGoingToSleep with pendingAuthenticated != null" + ) + } } private fun wakeAndUnlockModeToString(mode: Int): String { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt index 379c78ad8d0e..51aca070b180 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt @@ -16,6 +16,7 @@ package com.android.keyguard.logging +import com.android.systemui.biometrics.AuthRippleController import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController import com.android.systemui.log.dagger.KeyguardLog import com.android.systemui.plugins.log.LogBuffer @@ -120,4 +121,29 @@ constructor( "type=${KeyguardIndicationRotateTextViewController.indicationTypeToString(type)}" } } + + fun notShowingUnlockRipple(keyguardNotShowing: Boolean, unlockNotAllowed: Boolean) { + buffer.log( + AuthRippleController.TAG, + LogLevel.DEBUG, + { + bool1 = keyguardNotShowing + bool2 = unlockNotAllowed + }, + { "Not showing unlock ripple: keyguardNotShowing: $bool1, unlockNotAllowed: $bool2" } + ) + } + + fun showingUnlockRippleAt(x: Int, y: Int, context: String) { + buffer.log( + AuthRippleController.TAG, + LogLevel.DEBUG, + { + int1 = x + int2 = y + str1 = context + }, + { "Showing unlock ripple with center (x, y): ($int1, $int2), context: $str1" } + ) + } } diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index e53f6adb62a4..2403d1116360 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -26,6 +26,7 @@ import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.KeyguardListenModel import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.keyguard.TrustGrantFlags +import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel import com.android.systemui.plugins.log.LogLevel.DEBUG @@ -33,18 +34,15 @@ import com.android.systemui.plugins.log.LogLevel.ERROR import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.plugins.log.LogLevel.VERBOSE import com.android.systemui.plugins.log.LogLevel.WARNING -import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject private const val TAG = "KeyguardUpdateMonitorLog" -/** - * Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] - */ -class KeyguardUpdateMonitorLogger @Inject constructor( - @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer -) { +/** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */ +class KeyguardUpdateMonitorLogger +@Inject +constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG) fun e(@CompileTimeConstant msg: String) = log(msg, ERROR) @@ -56,15 +54,16 @@ class KeyguardUpdateMonitorLogger @Inject constructor( fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg) fun logActiveUnlockTriggered(reason: String?) { - logBuffer.log("ActiveUnlock", DEBUG, - { str1 = reason }, - { "initiate active unlock triggerReason=$str1" }) + logBuffer.log( + "ActiveUnlock", + DEBUG, + { str1 = reason }, + { "initiate active unlock triggerReason=$str1" } + ) } fun logAuthInterruptDetected(active: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = active }, - { "onAuthInterruptDetected($bool1)" }) + logBuffer.log(TAG, DEBUG, { bool1 = active }, { "onAuthInterruptDetected($bool1)" }) } fun logBroadcastReceived(action: String?) { @@ -72,9 +71,12 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logDeviceProvisionedState(deviceProvisioned: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = deviceProvisioned }, - { "DEVICE_PROVISIONED state = $bool1" }) + logBuffer.log( + TAG, + DEBUG, + { bool1 = deviceProvisioned }, + { "DEVICE_PROVISIONED state = $bool1" } + ) } fun logException(ex: Exception, @CompileTimeConstant logMsg: String) { @@ -82,46 +84,56 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFaceAcquired(acquireInfo: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = acquireInfo }, - { "Face acquired acquireInfo=$int1" }) + logBuffer.log(TAG, DEBUG, { int1 = acquireInfo }, { "Face acquired acquireInfo=$int1" }) } fun logFaceAuthDisabledForUser(userId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = userId }, - { "Face authentication disabled by DPM for userId: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = userId }, + { "Face authentication disabled by DPM for userId: $int1" } + ) } fun logFaceAuthError(msgId: Int, originalErrMsg: String) { - logBuffer.log(TAG, DEBUG, { - str1 = originalErrMsg - int1 = msgId - }, { "Face error received: $str1 msgId= $int1" }) + logBuffer.log( + TAG, + DEBUG, + { + str1 = originalErrMsg + int1 = msgId + }, + { "Face error received: $str1 msgId= $int1" } + ) } fun logFaceAuthForWrongUser(authUserId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = authUserId }, - { "Face authenticated for wrong user: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = authUserId }, + { "Face authenticated for wrong user: $int1" } + ) } fun logFaceAuthHelpMsg(msgId: Int, helpMsg: String?) { - logBuffer.log(TAG, DEBUG, { - int1 = msgId - str1 = helpMsg - }, { "Face help received, msgId: $int1 msg: $str1" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = msgId + str1 = helpMsg + }, + { "Face help received, msgId: $int1 msg: $str1" } + ) } fun logFaceAuthRequested(reason: String?) { - logBuffer.log(TAG, DEBUG, { - str1 = reason - }, { "requestFaceAuth() reason=$str1" }) + logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" }) } fun logFaceAuthSuccess(userId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = userId }, - { "Face auth succeeded for user $int1" }) + logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" }) } fun logFaceLockoutReset(@LockoutMode mode: Int) { @@ -133,21 +145,30 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = isFaceUnlockPossible }, - {"isUnlockWithFacePossible: $bool1"}) + logBuffer.log( + TAG, + DEBUG, + { bool1 = isFaceUnlockPossible }, + { "isUnlockWithFacePossible: $bool1" } + ) } fun logFingerprintAuthForWrongUser(authUserId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = authUserId }, - { "Fingerprint authenticated for wrong user: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = authUserId }, + { "Fingerprint authenticated for wrong user: $int1" } + ) } fun logFingerprintDisabledForUser(userId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = userId }, - { "Fingerprint disabled by DPM for userId: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = userId }, + { "Fingerprint disabled by DPM for userId: $int1" } + ) } fun logFingerprintLockoutReset(@LockoutMode mode: Int) { @@ -155,16 +176,24 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFingerprintRunningState(fingerprintRunningState: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = fingerprintRunningState }, - { "fingerprintRunningState: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = fingerprintRunningState }, + { "fingerprintRunningState: $int1" } + ) } fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) { - logBuffer.log(TAG, DEBUG, { - int1 = userId - bool1 = isStrongBiometric - }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"}) + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + bool1 = isStrongBiometric + }, + { "Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1" } + ) } fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) { @@ -182,29 +211,42 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFingerprintError(msgId: Int, originalErrMsg: String) { - logBuffer.log(TAG, DEBUG, { - str1 = originalErrMsg - int1 = msgId - }, { "Fingerprint error received: $str1 msgId= $int1" }) + logBuffer.log( + TAG, + DEBUG, + { + str1 = originalErrMsg + int1 = msgId + }, + { "Fingerprint error received: $str1 msgId= $int1" } + ) } fun logInvalidSubId(subId: Int) { - logBuffer.log(TAG, INFO, - { int1 = subId }, - { "Previously active sub id $int1 is now invalid, will remove" }) + logBuffer.log( + TAG, + INFO, + { int1 = subId }, + { "Previously active sub id $int1 is now invalid, will remove" } + ) } fun logPrimaryKeyguardBouncerChanged( - primaryBouncerIsOrWillBeShowing: Boolean, - primaryBouncerFullyShown: Boolean + primaryBouncerIsOrWillBeShowing: Boolean, + primaryBouncerFullyShown: Boolean ) { - logBuffer.log(TAG, DEBUG, { - bool1 = primaryBouncerIsOrWillBeShowing - bool2 = primaryBouncerFullyShown - }, { - "handlePrimaryBouncerChanged " + + logBuffer.log( + TAG, + DEBUG, + { + bool1 = primaryBouncerIsOrWillBeShowing + bool2 = primaryBouncerFullyShown + }, + { + "handlePrimaryBouncerChanged " + "primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2" - }) + } + ) } fun logKeyguardListenerModel(model: KeyguardListenModel) { @@ -212,98 +254,134 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) { - logBuffer.log(TAG, DEBUG, { - bool1 = showing - bool2 = occluded - bool3 = visible - }, { - "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" - }) + logBuffer.log( + TAG, + DEBUG, + { + bool1 = showing + bool2 = occluded + bool3 = visible + }, + { "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" } + ) } fun logMissingSupervisorAppError(userId: Int) { - logBuffer.log(TAG, ERROR, - { int1 = userId }, - { "No Profile Owner or Device Owner supervision app found for User $int1" }) + logBuffer.log( + TAG, + ERROR, + { int1 = userId }, + { "No Profile Owner or Device Owner supervision app found for User $int1" } + ) } fun logPhoneStateChanged(newState: String?) { - logBuffer.log(TAG, DEBUG, - { str1 = newState }, - { "handlePhoneStateChanged($str1)" }) + logBuffer.log(TAG, DEBUG, { str1 = newState }, { "handlePhoneStateChanged($str1)" }) } fun logRegisterCallback(callback: KeyguardUpdateMonitorCallback?) { - logBuffer.log(TAG, VERBOSE, - { str1 = "$callback" }, - { "*** register callback for $str1" }) + logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" }) } fun logRetryingAfterFaceHwUnavailable(retryCount: Int) { - logBuffer.log(TAG, WARNING, - { int1 = retryCount }, - { "Retrying face after HW unavailable, attempt $int1" }) + logBuffer.log( + TAG, + WARNING, + { int1 = retryCount }, + { "Retrying face after HW unavailable, attempt $int1" } + ) } fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) { - logBuffer.log(TAG, DEBUG, { - int1 = msgId - int2 = delay - str1 = "$errString" - }, { - "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" - }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = msgId + int2 = delay + str1 = "$errString" + }, + { "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" } + ) } fun logRetryAfterFpHwUnavailable(retryCount: Int) { - logBuffer.log(TAG, WARNING, - { int1 = retryCount }, - { "Retrying fingerprint attempt: $int1" }) + logBuffer.log( + TAG, + WARNING, + { int1 = retryCount }, + { "Retrying fingerprint attempt: $int1" } + ) } fun logSendPrimaryBouncerChanged( primaryBouncerIsOrWillBeShowing: Boolean, primaryBouncerFullyShown: Boolean, ) { - logBuffer.log(TAG, DEBUG, { - bool1 = primaryBouncerIsOrWillBeShowing - bool2 = primaryBouncerFullyShown - }, { - "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " + + logBuffer.log( + TAG, + DEBUG, + { + bool1 = primaryBouncerIsOrWillBeShowing + bool2 = primaryBouncerFullyShown + }, + { + "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " + "primaryBouncerFullyShown=$bool2" - }) + } + ) } fun logServiceStateChange(subId: Int, serviceState: ServiceState?) { - logBuffer.log(TAG, DEBUG, { - int1 = subId - str1 = "$serviceState" - }, { "handleServiceStateChange(subId=$int1, serviceState=$str1)" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = subId + str1 = "$serviceState" + }, + { "handleServiceStateChange(subId=$int1, serviceState=$str1)" } + ) } fun logServiceStateIntent(action: String?, serviceState: ServiceState?, subId: Int) { - logBuffer.log(TAG, VERBOSE, { - str1 = action - str2 = "$serviceState" - int1 = subId - }, { "action $str1 serviceState=$str2 subId=$int1" }) + logBuffer.log( + TAG, + VERBOSE, + { + str1 = action + str2 = "$serviceState" + int1 = subId + }, + { "action $str1 serviceState=$str2 subId=$int1" } + ) } fun logSimState(subId: Int, slotId: Int, state: Int) { - logBuffer.log(TAG, DEBUG, { - int1 = subId - int2 = slotId - long1 = state.toLong() - }, { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = subId + int2 = slotId + long1 = state.toLong() + }, + { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" } + ) } fun logSimStateFromIntent(action: String?, extraSimState: String?, slotId: Int, subId: Int) { - logBuffer.log(TAG, VERBOSE, { - str1 = action - str2 = extraSimState - int1 = slotId - int2 = subId - }, { "action $str1 state: $str2 slotId: $int1 subid: $int2" }) + logBuffer.log( + TAG, + VERBOSE, + { + str1 = action + str2 = extraSimState + int1 = slotId + int2 = subId + }, + { "action $str1 state: $str2 slotId: $int1 subid: $int2" } + ) } fun logSimUnlocked(subId: Int) { @@ -311,78 +389,98 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) { - logBuffer.log(TAG, VERBOSE, { - int1 = faceRunningState - str1 = faceAuthUiEvent.reason - str2 = faceAuthUiEvent.extraInfoToString() - }, { "startListeningForFace(): $int1, reason: $str1 $str2" }) + logBuffer.log( + TAG, + VERBOSE, + { + int1 = faceRunningState + str1 = faceAuthUiEvent.reason + str2 = faceAuthUiEvent.extraInfoToString() + }, + { "startListeningForFace(): $int1, reason: $str1 $str2" } + ) } fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) { - logBuffer.log(TAG, VERBOSE, { - int1 = faceRunningState - str1 = PowerManager.wakeReasonToString(pmWakeReason) - }, { "startListeningForFace(): $int1, reason: wakeUp-$str1" }) + logBuffer.log( + TAG, + VERBOSE, + { + int1 = faceRunningState + str1 = PowerManager.wakeReasonToString(pmWakeReason) + }, + { "startListeningForFace(): $int1, reason: wakeUp-$str1" } + ) } fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) { - logBuffer.log(TAG, VERBOSE, { - int1 = faceRunningState - str1 = faceAuthReason - }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }) + logBuffer.log( + TAG, + VERBOSE, + { + int1 = faceRunningState + str1 = faceAuthReason + }, + { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" } + ) } fun logSubInfo(subInfo: SubscriptionInfo?) { - logBuffer.log(TAG, VERBOSE, - { str1 = "$subInfo" }, - { "SubInfo:$str1" }) + logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" }) } fun logTimeFormatChanged(newTimeFormat: String?) { - logBuffer.log(TAG, DEBUG, - { str1 = newTimeFormat }, - { "handleTimeFormatUpdate timeFormat=$str1" }) + logBuffer.log( + TAG, + DEBUG, + { str1 = newTimeFormat }, + { "handleTimeFormatUpdate timeFormat=$str1" } + ) } fun logUdfpsPointerDown(sensorId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = sensorId }, - { "onUdfpsPointerDown, sensorId: $int1" }) + logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerDown, sensorId: $int1" }) } fun logUdfpsPointerUp(sensorId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = sensorId }, - { "onUdfpsPointerUp, sensorId: $int1" }) + logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" }) } fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) { - logBuffer.log(TAG, ERROR, { - int1 = faceRunningState - bool1 = unlockPossible - }, { - "Cancellation signal is not null, high chance of bug in " + - "face auth lifecycle management. " + - "Face state: $int1, unlockPossible: $bool1" - }) + logBuffer.log( + TAG, + ERROR, + { + int1 = faceRunningState + bool1 = unlockPossible + }, + { + "Cancellation signal is not null, high chance of bug in " + + "face auth lifecycle management. " + + "Face state: $int1, unlockPossible: $bool1" + } + ) } fun logUnexpectedFpCancellationSignalState( fingerprintRunningState: Int, unlockPossible: Boolean ) { - logBuffer.log(TAG, ERROR, { - int1 = fingerprintRunningState - bool1 = unlockPossible - }, { - "Cancellation signal is not null, high chance of bug in " + - "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1" - }) + logBuffer.log( + TAG, + ERROR, + { + int1 = fingerprintRunningState + bool1 = unlockPossible + }, + { + "Cancellation signal is not null, high chance of bug in " + + "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1" + } + ) } fun logUnregisterCallback(callback: KeyguardUpdateMonitorCallback?) { - logBuffer.log(TAG, VERBOSE, - { str1 = "$callback" }, - { "*** unregister callback for $str1" }) + logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** unregister callback for $str1" }) } fun logUserRequestedUnlock( @@ -390,75 +488,173 @@ class KeyguardUpdateMonitorLogger @Inject constructor( reason: String?, dismissKeyguard: Boolean ) { - logBuffer.log("ActiveUnlock", DEBUG, { - str1 = requestOrigin?.name - str2 = reason - bool1 = dismissKeyguard - }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" }) + logBuffer.log( + "ActiveUnlock", + DEBUG, + { + str1 = requestOrigin?.name + str2 = reason + bool1 = dismissKeyguard + }, + { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" } + ) } fun logTrustGrantedWithFlags( - flags: Int, - newlyUnlocked: Boolean, - userId: Int, - message: String? + flags: Int, + newlyUnlocked: Boolean, + userId: Int, + message: String? ) { - logBuffer.log(TAG, DEBUG, { - int1 = flags - bool1 = newlyUnlocked - int2 = userId - str1 = message - }, { "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " + - "flags=${TrustGrantFlags(int1)} message=$str1" }) - } - - fun logTrustChanged( - wasTrusted: Boolean, - isNowTrusted: Boolean, - userId: Int - ) { - logBuffer.log(TAG, DEBUG, { - bool1 = wasTrusted - bool2 = isNowTrusted - int1 = userId - }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = flags + bool1 = newlyUnlocked + int2 = userId + str1 = message + }, + { + "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " + + "flags=${TrustGrantFlags(int1)} message=$str1" + } + ) + } + + fun logTrustChanged(wasTrusted: Boolean, isNowTrusted: Boolean, userId: Int) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = wasTrusted + bool2 = isNowTrusted + int1 = userId + }, + { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" } + ) } fun logKeyguardStateUpdate( - secure: Boolean, - canDismissLockScreen: Boolean, - trusted: Boolean, - trustManaged: Boolean - + secure: Boolean, + canDismissLockScreen: Boolean, + trusted: Boolean, + trustManaged: Boolean ) { - logBuffer.log("KeyguardState", DEBUG, { - bool1 = secure - bool2 = canDismissLockScreen - bool3 = trusted - bool4 = trustManaged - }, { "#update secure=$bool1 canDismissKeyguard=$bool2" + - " trusted=$bool3 trustManaged=$bool4" }) + logBuffer.log( + "KeyguardState", + DEBUG, + { + bool1 = secure + bool2 = canDismissLockScreen + bool3 = trusted + bool4 = trustManaged + }, + { + "#update secure=$bool1 canDismissKeyguard=$bool2" + + " trusted=$bool3 trustManaged=$bool4" + } + ) } fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) { - logBuffer.log(TAG, VERBOSE, { - str1 = PowerManager.wakeReasonToString(pmWakeReason) - }, { "Skip updating face listening state on wakeup from $str1"}) + logBuffer.log( + TAG, + VERBOSE, + { str1 = PowerManager.wakeReasonToString(pmWakeReason) }, + { "Skip updating face listening state on wakeup from $str1" } + ) } fun logTaskStackChangedForAssistant(assistantVisible: Boolean) { - logBuffer.log(TAG, VERBOSE, { - bool1 = assistantVisible - }, { - "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" - }) + logBuffer.log( + TAG, + VERBOSE, + { bool1 = assistantVisible }, + { "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" } + ) } fun logAssistantVisible(assistantVisible: Boolean) { - logBuffer.log(TAG, VERBOSE, { - bool1 = assistantVisible - }, { - "Updating mAssistantVisible to new value: $bool1" - }) + logBuffer.log( + TAG, + VERBOSE, + { bool1 = assistantVisible }, + { "Updating mAssistantVisible to new value: $bool1" } + ) + } + + fun logReportSuccessfulBiometricUnlock(isStrongBiometric: Boolean, userId: Int) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = isStrongBiometric + int1 = userId + }, + { "reporting successful biometric unlock: isStrongBiometric: $bool1, userId: $int1" } + ) + } + + fun logHandlerHasAuthContinueMsgs(action: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = action }, + { + "MSG_BIOMETRIC_AUTHENTICATION_CONTINUE already queued up, " + + "ignoring updating FP listening state to $int1" + } + ) + } + + fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = oldValue + bool2 = newValue + }, + { "Face enrolled state changed: old: $bool1, new: $bool2" } + ) + } + + fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + bool1 = oldValue + bool2 = newValue + }, + { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" } + ) + } + + fun logTrustUsuallyManagedUpdated( + userId: Int, + oldValue: Boolean, + newValue: Boolean, + context: String + ) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + bool1 = oldValue + bool2 = newValue + str1 = context + }, + { + "trustUsuallyManaged changed for " + + "userId: $int1 " + + "old: $bool1, " + + "new: $bool2 " + + "context: $context" + } + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index b111e1f72f1d..d811d30b5693 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -37,6 +37,8 @@ import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; @@ -1398,6 +1400,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mWindowMagnifierCallback.onPerformScaleAction(mDisplayId, A11Y_ACTION_SCALE_RANGE.clamp(scale)); } + + @Override + public void onSettingsPanelVisibilityChanged(boolean shown) { + updateDragHandleResourcesIfNeeded(/* settingsPanelIsShown= */ shown); + } }; @Override @@ -1436,6 +1443,20 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } } + private void updateDragHandleResourcesIfNeeded(boolean settingsPanelIsShown) { + mDragView.setBackground(mContext.getResources().getDrawable(settingsPanelIsShown + ? R.drawable.accessibility_window_magnification_drag_handle_background_change + : R.drawable.accessibility_window_magnification_drag_handle_background)); + + PorterDuffColorFilter filter = new PorterDuffColorFilter( + mContext.getColor(settingsPanelIsShown + ? R.color.magnification_border_color + : R.color.magnification_drag_handle_stroke), + PorterDuff.Mode.SRC_ATOP); + + mDragView.setColorFilter(filter); + } + private void animateBounceEffect() { final ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mMirrorView, PropertyValuesHolder.ofFloat(View.SCALE_X, 1, mBounceEffectAnimationScale, 1), @@ -1468,7 +1489,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold super.onInitializeAccessibilityNodeInfo(host, info); final AccessibilityAction clickAction = new AccessibilityAction( AccessibilityAction.ACTION_CLICK.getId(), mContext.getResources().getString( - R.string.magnification_mode_switch_click_label)); + R.string.magnification_open_settings_click_label)); info.addAction(clickAction); info.setClickable(true); info.addAction( diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java index 15264e64a241..9ad64e293fe5 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java @@ -215,9 +215,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest private boolean performA11yAction(View view, int action) { final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); - if (action == AccessibilityAction.ACTION_CLICK.getId()) { - handleSingleTap(view); - } else if (action == R.id.accessibility_action_move_up) { + if (action == R.id.accessibility_action_move_up) { moveButton(0, -windowBounds.height()); } else if (action == R.id.accessibility_action_move_down) { moveButton(0, windowBounds.height()); @@ -264,8 +262,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest } else if (id == R.id.magnifier_full_button) { hideSettingPanel(); toggleMagnificationMode(); - } else { - hideSettingPanel(); } } }; @@ -273,7 +269,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest @Override public boolean onSingleTap(View view) { mSingleTapDetected = true; - handleSingleTap(view); return true; } @@ -328,6 +323,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest } mContext.unregisterReceiver(mScreenOffReceiver); + mCallback.onSettingsPanelVisibilityChanged(/* shown= */ false); } public void showSettingPanel() { @@ -358,10 +354,15 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest } mWindowManager.addView(mSettingView, mParams); + if (resetPosition) { + // Request focus on the settings panel when position of the panel is reset. + mSettingView.requestFocus(); + } // Exclude magnification switch button from system gesture area. setSystemGestureExclusion(); mIsVisible = true; + mCallback.onSettingsPanelVisibilityChanged(/* shown= */ true); } mContext.registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); } @@ -385,8 +386,8 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest mSettingView = (LinearLayout) View.inflate(mContext, R.layout.window_magnification_settings_view, null); - mSettingView.setClickable(true); mSettingView.setFocusable(true); + mSettingView.setFocusableInTouchMode(true); mSettingView.setOnTouchListener(this::onTouch); mPanelView = mSettingView.findViewById(R.id.magnifier_panel_view); @@ -499,22 +500,6 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest } } - private void handleSingleTap(View view) { - int id = view.getId(); - if (id == R.id.magnifier_small_button) { - setMagnifierSize(MagnificationSize.SMALL); - } else if (id == R.id.magnifier_medium_button) { - setMagnifierSize(MagnificationSize.MEDIUM); - } else if (id == R.id.magnifier_large_button) { - setMagnifierSize(MagnificationSize.LARGE); - } else if (id == R.id.magnifier_full_button) { - hideSettingPanel(); - toggleMagnificationMode(); - } else { - hideSettingPanel(); - } - } - public void editMagnifierSizeMode(boolean enable) { setEditMagnifierSizeMode(enable); updateSelectedButton(MagnificationSize.NONE); @@ -551,7 +536,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, - LayoutParams.FLAG_NOT_FOCUSABLE, + /* _flags= */ 0, PixelFormat.TRANSPARENT); params.gravity = Gravity.TOP | Gravity.START; params.accessibilityTitle = getAccessibilityWindowTitle(context); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java index 22ec65001101..1d833402b1f4 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java @@ -61,4 +61,11 @@ public interface WindowMagnificationSettingsCallback { * 1 : ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, 2 : ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW */ void onModeSwitch(int newMode); + + /** + * Called when the visibility of the magnification settings panel changed. + * + * @param shown The visibility of the magnification settings panel. + */ + void onSettingsPanelVisibilityChanged(boolean shown); } diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java index ce4253477a41..0002ae95f476 100644 --- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java @@ -38,7 +38,6 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; -import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -347,10 +346,9 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { } if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); updatePercentText(); - addView(mBatteryPercentView, - new ViewGroup.LayoutParams( - LayoutParams.WRAP_CONTENT, - LayoutParams.MATCH_PARENT)); + addView(mBatteryPercentView, new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT)); } } else { if (showing) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index d561cd7af7f0..93b57dc127dd 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricSourceType import androidx.annotation.VisibleForTesting import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.keyguard.logging.KeyguardLogger import com.android.settingslib.Utils import com.android.systemui.R import com.android.systemui.animation.Interpolators @@ -74,6 +75,7 @@ class AuthRippleController @Inject constructor( private val udfpsControllerProvider: Provider<UdfpsController>, private val statusBarStateController: StatusBarStateController, private val featureFlags: FeatureFlags, + private val logger: KeyguardLogger, rippleView: AuthRippleView? ) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback, WakefulnessLifecycle.Observer { @@ -120,8 +122,11 @@ class AuthRippleController @Inject constructor( } fun showUnlockRipple(biometricSourceType: BiometricSourceType) { - if (!keyguardStateController.isShowing || - !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(biometricSourceType)) { + val keyguardNotShowing = !keyguardStateController.isShowing + val unlockNotAllowed = !keyguardUpdateMonitor + .isUnlockingWithBiometricAllowed(biometricSourceType) + if (keyguardNotShowing || unlockNotAllowed) { + logger.notShowingUnlockRipple(keyguardNotShowing, unlockNotAllowed) return } @@ -138,6 +143,7 @@ class AuthRippleController @Inject constructor( Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y) ) ) + logger.showingUnlockRippleAt(it.x, it.y, "FP sensor radius: $udfpsRadius") showUnlockedRipple() } } else if (biometricSourceType == BiometricSourceType.FACE) { @@ -155,6 +161,7 @@ class AuthRippleController @Inject constructor( Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y) ) ) + logger.showingUnlockRippleAt(it.x, it.y, "Face unlock ripple") showUnlockedRipple() } } @@ -391,5 +398,6 @@ class AuthRippleController @Inject constructor( companion object { const val RIPPLE_ANIMATION_DURATION: Long = 1533 + const val TAG = "AuthRippleController" } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java index bc0f9950f865..f83885b7bb32 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java @@ -38,6 +38,7 @@ import javax.inject.Inject; public class FalsingDataProvider { private static final long MOTION_EVENT_AGE_MS = 1000; + private static final long DROP_EVENT_THRESHOLD_MS = 50; private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI); private final int mWidthPixels; @@ -60,6 +61,7 @@ public class FalsingDataProvider { private float mAngle = 0; private MotionEvent mFirstRecentMotionEvent; private MotionEvent mLastMotionEvent; + private boolean mDropLastEvent; private boolean mJustUnlockedWithFace; private boolean mA11YAction; @@ -95,6 +97,12 @@ public class FalsingDataProvider { // Ensure prior gesture was completed. May be a no-op. completePriorGesture(); } + + // Drop the gesture closing event if it is close in time to a previous ACTION_MOVE event. + // The reason is that the closing ACTION_UP event of a swipe can be a bit offseted from the + // previous ACTION_MOVE event and when it happens, it makes some classifiers fail. + mDropLastEvent = shouldDropEvent(motionEvent); + mRecentMotionEvents.addAll(motionEvents); FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size()); @@ -129,6 +137,7 @@ public class FalsingDataProvider { mPriorMotionEvents = mRecentMotionEvents; mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS); } + mDropLastEvent = false; mA11YAction = false; } @@ -150,8 +159,18 @@ public class FalsingDataProvider { return mYdpi; } + /** + * Get the {@link MotionEvent}s of the most recent gesture. + * + * Note that this list may not include the last recorded event. + * @see #mDropLastEvent + */ public List<MotionEvent> getRecentMotionEvents() { - return mRecentMotionEvents; + if (!mDropLastEvent || mRecentMotionEvents.isEmpty()) { + return mRecentMotionEvents; + } else { + return mRecentMotionEvents.subList(0, mRecentMotionEvents.size() - 1); + } } public List<MotionEvent> getPriorMotionEvents() { @@ -169,7 +188,12 @@ public class FalsingDataProvider { return mFirstRecentMotionEvent; } - /** Get the last recorded {@link MotionEvent}. */ + /** + * Get the last {@link MotionEvent} of the most recent gesture. + * + * Note that this may be the event prior to the last recorded event. + * @see #mDropLastEvent + */ public MotionEvent getLastMotionEvent() { recalculateData(); return mLastMotionEvent; @@ -236,12 +260,13 @@ public class FalsingDataProvider { return; } - if (mRecentMotionEvents.isEmpty()) { + List<MotionEvent> recentMotionEvents = getRecentMotionEvents(); + if (recentMotionEvents.isEmpty()) { mFirstRecentMotionEvent = null; mLastMotionEvent = null; } else { - mFirstRecentMotionEvent = mRecentMotionEvents.get(0); - mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1); + mFirstRecentMotionEvent = recentMotionEvents.get(0); + mLastMotionEvent = recentMotionEvents.get(recentMotionEvents.size() - 1); } calculateAngleInternal(); @@ -249,6 +274,17 @@ public class FalsingDataProvider { mDirty = false; } + private boolean shouldDropEvent(MotionEvent event) { + if (mRecentMotionEvents.size() < 3) return false; + + MotionEvent lastEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1); + boolean isCompletingGesture = event.getActionMasked() == MotionEvent.ACTION_UP + && lastEvent.getActionMasked() == MotionEvent.ACTION_MOVE; + boolean isRecentEvent = + event.getEventTime() - lastEvent.getEventTime() < DROP_EVENT_THRESHOLD_MS; + return isCompletingGesture && isRecentEvent; + } + private void calculateAngleInternal() { if (mRecentMotionEvents.size() < 2) { mAngle = Float.MAX_VALUE; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java index 4773f2a3b13e..51aede79b581 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java @@ -183,7 +183,7 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> { @Override public List<MotionEvent> subList(int fromIndex, int toIndex) { - throw new UnsupportedOperationException(); + return mMotionEvents.subList(fromIndex, toIndex); } class Iter implements ListIterator<MotionEvent> { diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index c214f5341450..2501be93d189 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -263,10 +263,11 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv @Override // ClipboardListener.ClipboardOverlay public void setClipData(ClipData data, String source) { ClipboardModel model = ClipboardModel.fromClipData(mContext, mClipboardUtils, data, source); - if (mExitAnimator != null && mExitAnimator.isRunning()) { + boolean wasExiting = (mExitAnimator != null && mExitAnimator.isRunning()); + if (wasExiting) { mExitAnimator.cancel(); } - boolean shouldAnimate = !model.dataMatches(mClipboardModel); + boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting; mClipboardModel = model; mClipboardLogger.setClipSource(mClipboardModel.getSource()); if (shouldAnimate) { @@ -313,15 +314,19 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv mOnPreviewTapped = this::editText; break; case IMAGE: - if (model.isSensitive() || model.loadThumbnail(mContext) != null) { - mView.showImagePreview( - model.isSensitive() ? null : model.loadThumbnail(mContext)); - mView.setEditAccessibilityAction(true); - mOnPreviewTapped = () -> editImage(model.getUri()); - } else { - // image loading failed - mView.showDefaultTextPreview(); - } + mBgExecutor.execute(() -> { + if (model.isSensitive() || model.loadThumbnail(mContext) != null) { + mView.post(() -> { + mView.showImagePreview( + model.isSensitive() ? null : model.loadThumbnail(mContext)); + mView.setEditAccessibilityAction(true); + }); + mOnPreviewTapped = () -> editImage(model.getUri()); + } else { + // image loading failed + mView.post(mView::showDefaultTextPreview); + } + }); break; case URI: case OTHER: @@ -363,15 +368,15 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv private void classifyText(ClipboardModel model) { mBgExecutor.execute(() -> { - Optional<RemoteAction> remoteAction = mClipboardUtils.getAction( - model.getText(), model.getTextLinks(), model.getSource()); + Optional<RemoteAction> remoteAction = + mClipboardUtils.getAction(model.getTextLinks(), model.getSource()); if (model.equals(mClipboardModel)) { remoteAction.ifPresent(action -> { mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN); - mView.setActionChip(action, () -> { + mView.post(() -> mView.setActionChip(action, () -> { mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED); animateOut(); - }); + })); }); } }); diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java index a85f8b9357f5..25caaeac2c38 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java @@ -39,6 +39,9 @@ import javax.inject.Inject; class ClipboardOverlayUtils { + // minimum proportion of entire text an entity must take up, to be considered for smart actions + private static final float MINIMUM_ENTITY_PROPORTION = .8f; + private final TextClassifier mTextClassifier; @Inject @@ -65,19 +68,23 @@ class ClipboardOverlayUtils { return false; } - public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) { - return getActions(text, textLinks).stream().filter(remoteAction -> { + public Optional<RemoteAction> getAction(TextLinks textLinks, String source) { + return getActions(textLinks).stream().filter(remoteAction -> { ComponentName component = remoteAction.getActionIntent().getIntent().getComponent(); return component != null && !TextUtils.equals(source, component.getPackageName()); }).findFirst(); } - private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) { + private ArrayList<RemoteAction> getActions(TextLinks textLinks) { ArrayList<RemoteAction> actions = new ArrayList<>(); for (TextLinks.TextLink link : textLinks.getLinks()) { - TextClassification classification = mTextClassifier.classifyText( - text, link.getStart(), link.getEnd(), null); - actions.addAll(classification.getActions()); + // skip classification for incidental entities + if (link.getEnd() - link.getStart() + >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) { + TextClassification classification = mTextClassifier.classifyText( + textLinks.getText(), link.getStart(), link.getEnd(), null); + actions.addAll(classification.getActions()); + } } return actions; } @@ -92,9 +99,13 @@ class ClipboardOverlayUtils { private ArrayList<RemoteAction> getActions(ClipData.Item item) { ArrayList<RemoteAction> actions = new ArrayList<>(); for (TextLinks.TextLink link : item.getTextLinks().getLinks()) { - TextClassification classification = mTextClassifier.classifyText( - item.getText(), link.getStart(), link.getEnd(), null); - actions.addAll(classification.getActions()); + // skip classification for incidental entities + if (link.getEnd() - link.getStart() + >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) { + TextClassification classification = mTextClassifier.classifyText( + item.getText(), link.getStart(), link.getEnd(), null); + actions.addAll(classification.getActions()); + } } return actions; } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index 72c3a943c30b..217f4d89e24c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -84,7 +84,7 @@ class ControlsProviderLifecycleManager( private val BIND_FLAGS_PANEL = Context.BIND_AUTO_CREATE or Context.BIND_NOT_PERCEPTIBLE } - private val intent = Intent().apply { + private val intent = Intent(ControlsProviderService.SERVICE_CONTROLS).apply { component = componentName putExtra(CALLBACK_BUNDLE, Bundle().apply { putBinder(CALLBACK_TOKEN, token) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index a5beb4e85058..3cf26b381d7d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -23,15 +23,16 @@ import com.android.systemui.hdmi.HdmiCecSetMenuLanguageActivity; import com.android.systemui.keyguard.WorkLockActivity; import com.android.systemui.people.PeopleSpaceActivity; import com.android.systemui.people.widget.LaunchConversationActivity; -import com.android.systemui.screenshot.AppClipsActivity; -import com.android.systemui.screenshot.AppClipsTrampolineActivity; import com.android.systemui.screenshot.LongScreenshotActivity; +import com.android.systemui.screenshot.appclips.AppClipsActivity; +import com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity; import com.android.systemui.sensorprivacy.SensorUseStartedActivity; import com.android.systemui.sensorprivacy.television.TvSensorPrivacyChangedActivity; import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity; import com.android.systemui.settings.brightness.BrightnessDialog; import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity; import com.android.systemui.tuner.TunerActivity; +import com.android.systemui.usb.UsbAccessoryUriActivity; import com.android.systemui.usb.UsbConfirmActivity; import com.android.systemui.usb.UsbDebuggingActivity; import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity; @@ -97,6 +98,12 @@ public abstract class DefaultActivityBinder { @ClassKey(UsbConfirmActivity.class) public abstract Activity bindUsbConfirmActivity(UsbConfirmActivity activity); + /** Inject into UsbAccessoryUriActivity. */ + @Binds + @IntoMap + @ClassKey(UsbAccessoryUriActivity.class) + public abstract Activity bindUsbAccessoryUriActivity(UsbAccessoryUriActivity activity); + /** Inject into CreateUserActivity. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index c96946bc22ae..7a1abf46bd93 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -75,6 +75,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.connectivity.ConnectivityModule; +import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; @@ -257,9 +258,7 @@ public abstract class SystemUIModule { abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider(); @BindsOptionalOf - //TODO(b/269430792 remove full qualifier. Full qualifier is used to avoid merge conflict.) - abstract com.android.systemui.statusbar.events.SystemStatusAnimationScheduler - optionalSystemStatusAnimationScheduler(); + abstract SystemStatusAnimationScheduler optionalSystemStatusAnimationScheduler(); @SysUISingleton @Binds diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index 73c2289ad6bd..a7b3bbcbc37b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -254,7 +254,10 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { mCurrentScrimController = mScrimManager.getCurrentController(); session.registerCallback(() -> { - mVelocityTracker.recycle(); + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } mScrimManager.removeCallback(mScrimManagerCallback); mCapture = null; mNotificationShadeWindowController.setForcePluginOpen(false, this); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index febb45ef5ce5..95b37ac5545d 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -438,7 +438,9 @@ object Flags { ) // TODO(b/256873975): Tracking Bug - @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar") + @JvmField + @Keep + val WM_BUBBLE_BAR = sysPropBooleanFlag(1111, "persist.wm.debug.bubble_bar", default = false) // TODO(b/260271148): Tracking bug @Keep @@ -461,7 +463,7 @@ object Flags { @Keep @JvmField val ENABLE_PIP_SIZE_LARGE_SCREEN = - sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = false) + sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = true) // TODO(b/265998256): Tracking bug @Keep @@ -625,11 +627,6 @@ object Flags { @JvmField val OUTPUT_SWITCHER_DEVICE_STATUS = releasedFlag(2502, "output_switcher_device_status") - // TODO(b/20911786): Tracking Bug - @JvmField - val OUTPUT_SWITCHER_SHOW_API_ENABLED = - releasedFlag(2503, "output_switcher_show_api_enabled", teamfood = true) - // 2700 - unfold transitions // TODO(b/265764985): Tracking Bug @Keep diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index 949bcfbd684d..e43f83b876ba 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -2056,6 +2056,10 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene || Intent.ACTION_SCREEN_OFF.equals(action)) { String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { + // These broadcasts are usually received when locking the device, swiping up to + // home (which collapses the shade), etc. In those cases, we usually don't want + // to animate this dialog back into the view, so we disable the exit animations. + mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason)); } } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt index b0f9c4edb073..d078688e5944 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt @@ -21,6 +21,7 @@ import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.keyboard.backlight.ui.KeyboardBacklightDialogCoordinator import javax.inject.Inject /** A [CoreStartable] that launches components interested in physical keyboard interaction. */ @@ -28,11 +29,12 @@ import javax.inject.Inject class PhysicalKeyboardCoreStartable @Inject constructor( + private val keyboardBacklightDialogCoordinator: KeyboardBacklightDialogCoordinator, private val featureFlags: FeatureFlags, ) : CoreStartable { override fun start() { if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) { - // TODO(b/268645743) start listening for keyboard backlight brightness + keyboardBacklightDialogCoordinator.startListening() } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt new file mode 100644 index 000000000000..65e70b319923 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.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.keyboard.backlight.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyboard.data.repository.KeyboardRepository +import com.android.systemui.keyboard.shared.model.BacklightModel +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf + +/** Allows listening to changes to keyboard backlight level */ +@SysUISingleton +class KeyboardBacklightInteractor +@Inject +constructor( + private val keyboardRepository: KeyboardRepository, +) { + + /** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */ + val backlight: Flow<BacklightModel?> = + keyboardRepository.keyboardConnected.flatMapLatest { connected -> + if (connected) keyboardRepository.backlight else flowOf(null) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt new file mode 100644 index 000000000000..85d0379a77db --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt @@ -0,0 +1,59 @@ +/* + * 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.keyboard.backlight.ui + +import android.content.Context +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog +import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight + * indicator + */ +@SysUISingleton +class KeyboardBacklightDialogCoordinator +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + private val context: Context, + private val viewModel: BacklightDialogViewModel, +) { + + var dialog: KeyboardBacklightDialog? = null + + fun startListening() { + applicationScope.launch { + viewModel.dialogContent.collect { dialogViewModel -> + if (dialogViewModel != null) { + if (dialog == null) { + dialog = KeyboardBacklightDialog(context, dialogViewModel) + // pass viewModel and show + } + } else { + dialog?.dismiss() + dialog = null + } + } + } + } +} diff --git a/services/people/java/com/android/server/people/data/PerPackageThrottler.java b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt index 3d6cd84d326a..b68a2a84b5d1 100644 --- a/services/people/java/com/android/server/people/data/PerPackageThrottler.java +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt @@ -12,17 +12,21 @@ * 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.people.data; +package com.android.systemui.keyboard.backlight.ui.view + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel -import android.util.Pair; +class KeyboardBacklightDialog(context: Context, val viewModel: BacklightDialogContentViewModel) : + Dialog(context) { -/** The interface for throttling expensive runnables per package. */ -interface PerPackageThrottler { - /** - * Schedule a runnable to run in the future, and debounce runnables for same {@code pkgUserId} - * that occur until that future has run. - */ - void scheduleDebounced(Pair<String, Integer> pkgUserId, Runnable runnable); + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // TODO(b/268650355) Implement the dialog + } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ElevationTokens.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt index e1e666ef908b..3ef0ca39b8f3 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ElevationTokens.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt @@ -12,18 +12,9 @@ * 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.credentialmanager.common.ui - -import androidx.compose.ui.unit.dp +package com.android.systemui.keyboard.backlight.ui.viewmodel -/** Copied from androidx.compose.material3.tokens. */ -internal object ElevationTokens { - val Level0 = 0.0.dp - val Level1 = 1.0.dp - val Level2 = 3.0.dp - val Level3 = 6.0.dp - val Level4 = 8.0.dp - val Level5 = 12.0.dp -}
\ No newline at end of file +data class BacklightDialogContentViewModel(val currentValue: Int, val maxValue: Int) diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt new file mode 100644 index 000000000000..86abca5faaf3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.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.keyboard.backlight.ui.viewmodel + +import android.view.accessibility.AccessibilityManager +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper +import javax.inject.Inject +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map + +/** + * Responsible for dialog visibility and content - emits [BacklightDialogContentViewModel] if dialog + * should be shown and hidden otherwise + */ +@SysUISingleton +class BacklightDialogViewModel +@Inject +constructor( + interactor: KeyboardBacklightInteractor, + private val accessibilityManagerWrapper: AccessibilityManagerWrapper, +) { + + private val timeoutMillis: Long + get() = + accessibilityManagerWrapper + .getRecommendedTimeoutMillis( + DEFAULT_DIALOG_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_ICONS + ) + .toLong() + + val dialogContent: Flow<BacklightDialogContentViewModel?> = + interactor.backlight + .filterNotNull() + .map { BacklightDialogContentViewModel(it.level, it.maxLevel) } + .timeout(timeoutMillis, emitAfterTimeout = null) + + private fun <T> Flow<T>.timeout(timeoutMillis: Long, emitAfterTimeout: T): Flow<T> { + return flatMapLatest { + flow { + emit(it) + delay(timeoutMillis) + emit(emitAfterTimeout) + } + } + } + + private companion object { + const val DEFAULT_DIALOG_TIMEOUT_MILLIS = 3000 + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt index 70faf406d621..b86083abad21 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt @@ -18,15 +18,19 @@ package com.android.systemui.keyboard.data.repository import android.hardware.input.InputManager +import android.hardware.input.InputManager.KeyboardBacklightListener +import android.hardware.input.KeyboardBacklightState 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.dagger.qualifiers.Background -import com.android.systemui.keyboard.data.model.BacklightModel +import com.android.systemui.keyboard.shared.model.BacklightModel +import java.util.concurrent.Executor import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -51,24 +55,22 @@ constructor( private val connectedDeviceIds: Flow<Set<Int>> = conflatedCallbackFlow { - fun send(element: Set<Int>) = trySendWithFailureLogging(element, TAG) - var connectedKeyboards = inputManager.inputDeviceIds.toSet() val listener = object : InputManager.InputDeviceListener { override fun onInputDeviceAdded(deviceId: Int) { connectedKeyboards = connectedKeyboards + deviceId - send(connectedKeyboards) + sendWithLogging(connectedKeyboards) } override fun onInputDeviceChanged(deviceId: Int) = Unit override fun onInputDeviceRemoved(deviceId: Int) { connectedKeyboards = connectedKeyboards - deviceId - send(connectedKeyboards) + sendWithLogging(connectedKeyboards) } } - send(connectedKeyboards) + sendWithLogging(connectedKeyboards) inputManager.registerInputDeviceListener(listener, /* handler= */ null) awaitClose { inputManager.unregisterInputDeviceListener(listener) } } @@ -78,6 +80,16 @@ constructor( replay = 1, ) + private val backlightStateListener: Flow<KeyboardBacklightState> = conflatedCallbackFlow { + val listener = KeyboardBacklightListener { _, state, isTriggeredByKeyPress -> + if (isTriggeredByKeyPress) { + sendWithLogging(state) + } + } + inputManager.registerKeyboardBacklightListener(Executor(Runnable::run), listener) + awaitClose { inputManager.unregisterKeyboardBacklightListener(listener) } + } + override val keyboardConnected: Flow<Boolean> = connectedDeviceIds .map { it.any { deviceId -> isPhysicalFullKeyboard(deviceId) } } @@ -85,9 +97,13 @@ constructor( .flowOn(backgroundDispatcher) override val backlight: Flow<BacklightModel> = - conflatedCallbackFlow { - // TODO(b/268645734) register BacklightListener - } + backlightStateListener + .map { BacklightModel(it.brightnessLevel, it.maxBrightnessLevel) } + .flowOn(backgroundDispatcher) + + private fun <T> SendChannel<T>.sendWithLogging(element: T) { + trySendWithFailureLogging(element, TAG) + } private fun isPhysicalFullKeyboard(deviceId: Int): Boolean { val device = inputManager.getInputDevice(deviceId) diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt index ea15a9f18584..4a32f79285e3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt @@ -15,7 +15,7 @@ * */ -package com.android.systemui.keyboard.data.model +package com.android.systemui.keyboard.shared.model /** * Model for current state of keyboard backlight brightness. [level] indicates current level of diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 2ad1ab722d55..377a136920f0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -966,13 +966,24 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { + if (!handleOnAnimationStart( + transit, apps, wallpapers, nonApps, finishedCallback)) { + // Usually we rely on animation completion to synchronize occluded status, + // but there was no animation to play, so just update it now. + setOccluded(true /* isOccluded */, false /* animate */); + } + } + + private boolean handleOnAnimationStart(int transit, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, + IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { if (apps == null || apps.length == 0 || apps[0] == null) { if (DEBUG) { Log.d(TAG, "No apps provided to the OccludeByDream runner; " + "skipping occluding animation."); } finishedCallback.onAnimationFinished(); - return; + return false; } final RemoteAnimationTarget primary = apps[0]; @@ -982,7 +993,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, Log.w(TAG, "The occluding app isn't Dream; " + "finishing up. Please check that the config is correct."); finishedCallback.onAnimationFinished(); - return; + return false; } final SyncRtSurfaceTransactionApplier applier = @@ -1031,6 +1042,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mOccludeByDreamAnimator.start(); }); + return true; } }; @@ -1917,20 +1929,24 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // If the keyguard is already showing, see if we don't need to bother re-showing it. Check // flags in both files to account for the hiding animation which results in a delay and - // discrepancy between flags. + // discrepancy between flags. If we're in the middle of hiding, do not short circuit so that + // we explicitly re-set state. if (mShowing && mKeyguardStateController.isShowing()) { - if (mPM.isInteractive()) { + if (mPM.isInteractive() && !mHiding) { // It's already showing, and we're not trying to show it while the screen is off. // We can simply reset all of the views. - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); + if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is " + + "already showing, we're interactive, and we were not previously hiding. " + + "It should be safe to short-circuit here."); resetStateLocked(); return; } else { - // We are trying to show the keyguard while the screen is off - this results from - // race conditions involving locking while unlocking. Don't short-circuit here and - // ensure the keyguard is fully re-shown. + // We are trying to show the keyguard while the screen is off or while we were in + // the middle of hiding - this results from race conditions involving locking while + // unlocking. Don't short-circuit here and ensure the keyguard is fully re-shown. Log.e(TAG, - "doKeyguard: already showing, but re-showing since we're not interactive"); + "doKeyguard: already showing, but re-showing because we're interactive or " + + "were in the middle of hiding."); } } @@ -2424,11 +2440,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, if (DEBUG) Log.d(TAG, "handleShow"); } - mHiding = false; mKeyguardExitAnimationRunner = null; mWakeAndUnlocking = false; setPendingLock(false); - setShowingLocked(true); + + // Force if we we're showing in the middle of hiding, to ensure we end up in the correct + // state. + setShowingLocked(true, mHiding /* force */); + if (mHiding) { + Log.d(TAG, "Forcing setShowingLocked because mHiding=true, which means we're " + + "showing in the middle of hiding."); + } + mHiding = false; + mKeyguardViewControllerLazy.get().show(options); resetKeyguardDonePendingLocked(); mHideAnimationRun = false; 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 47ef0fac17ab..cb891063385f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -46,6 +46,8 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffor import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule; import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule; import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule; +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger; +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; @@ -64,6 +66,8 @@ import java.util.concurrent.Executor; import dagger.Lazy; import dagger.Module; import dagger.Provides; +import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.CoroutineScope; /** * Dagger Module providing keyguard. @@ -153,4 +157,10 @@ public class KeyguardModule { public ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) { return viewMediator.getViewMediatorCallback(); } + + /** */ + @Provides + public KeyguardQuickAffordancesMetricsLogger providesKeyguardQuickAffordancesMetricsLogger() { + return new KeyguardQuickAffordancesMetricsLoggerImpl(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt index bc3c7203ce3d..1735b5dba094 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt @@ -37,6 +37,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardPickerFlag import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract @@ -68,6 +69,7 @@ constructor( private val featureFlags: FeatureFlags, private val repository: Lazy<KeyguardQuickAffordanceRepository>, private val launchAnimator: DialogLaunchAnimator, + private val logger: KeyguardQuickAffordancesMetricsLogger, private val devicePolicyManager: DevicePolicyManager, @Background private val backgroundDispatcher: CoroutineDispatcher, ) { @@ -122,10 +124,12 @@ constructor( * @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of * the affordance that was clicked * @param expandable An optional [Expandable] for the activity- or dialog-launch animation + * @param slotId The id of the lockscreen slot that the affordance is in */ fun onQuickAffordanceTriggered( configKey: String, expandable: Expandable?, + slotId: String, ) { @Suppress("UNCHECKED_CAST") val config = @@ -139,6 +143,7 @@ constructor( Log.e(TAG, "Affordance config with key of \"$configKey\" not found!") return } + logger.logOnShortcutTriggered(slotId, configKey) when (val result = config.onTriggered(expandable)) { is KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity -> @@ -191,6 +196,7 @@ constructor( affordanceIds = selections, ) + logger.logOnShortcutSelected(slotId, affordanceId) return true } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancesMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancesMetricsLogger.kt new file mode 100644 index 000000000000..0b0225a51412 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancesMetricsLogger.kt @@ -0,0 +1,58 @@ +/* + * 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.quickaffordance + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.shared.system.SysUiStatsLog + +interface KeyguardQuickAffordancesMetricsLogger { + + /** + * Logs shortcut Triggered + * @param slotId The id of the lockscreen slot that the affordance is in + * @param affordanceId The id of the lockscreen affordance + */ + fun logOnShortcutTriggered(slotId: String, affordanceId: String) + + /** + * Logs shortcut Selected + * @param slotId The id of the lockscreen slot that the affordance is in + * @param affordanceId The id of the lockscreen affordance + */ + fun logOnShortcutSelected(slotId: String, affordanceId: String) + +} + +@SysUISingleton +class KeyguardQuickAffordancesMetricsLoggerImpl : KeyguardQuickAffordancesMetricsLogger { + + override fun logOnShortcutTriggered(slotId: String, affordanceId: String) { + SysUiStatsLog.write( + SysUiStatsLog.LOCKSCREEN_SHORTCUT_TRIGGERED, + slotId, + affordanceId, + ) + } + + override fun logOnShortcutSelected(slotId: String, affordanceId: String) { + SysUiStatsLog.write( + SysUiStatsLog.LOCKSCREEN_SHORTCUT_SELECTED, + slotId, + affordanceId, + ) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index ca1e27c9d19c..38b9d508f81c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -47,6 +47,7 @@ class KeyguardTransitionAnimationFlow( duration: Duration, onStep: (Float) -> Float, startTime: Duration = 0.milliseconds, + onStart: (() -> Unit)? = null, onCancel: (() -> Float)? = null, onFinish: (() -> Float)? = null, interpolator: Interpolator = LINEAR, @@ -73,6 +74,7 @@ class KeyguardTransitionAnimationFlow( // the ViewModels of the last update STARTED -> { isComplete = false + onStart?.invoke() max(0f, min(1f, value)) } // Always send a final value of 1. Because of rounding, [value] may never be diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index ab009f4a6a66..d63636c6fccc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -342,7 +342,13 @@ object KeyguardBottomAreaViewBinder { if (viewModel.isClickable) { if (viewModel.useLongPress) { view.setOnTouchListener( - OnTouchListener(view, viewModel, messageDisplayer, vibratorHelper) + OnTouchListener( + view, + viewModel, + messageDisplayer, + vibratorHelper, + falsingManager, + ) ) } else { view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager))) @@ -371,6 +377,7 @@ object KeyguardBottomAreaViewBinder { private val viewModel: KeyguardQuickAffordanceViewModel, private val messageDisplayer: (Int) -> Unit, private val vibratorHelper: VibratorHelper?, + private val falsingManager: FalsingManager?, ) : View.OnTouchListener { private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong() @@ -395,7 +402,14 @@ object KeyguardBottomAreaViewBinder { .scaleY(PRESSED_SCALE) .setDuration(longPressDurationMs) .withEndAction { - dispatchClick(viewModel.configKey) + if ( + falsingManager + ?.isFalseLongTap( + FalsingManager.MODERATE_PENALTY + ) == false + ) { + dispatchClick(viewModel.configKey) + } cancel() } } @@ -421,7 +435,8 @@ object KeyguardBottomAreaViewBinder { // the pointer performs a click. if ( viewModel.configKey != null && - distanceMoved(event) <= ViewConfiguration.getTouchSlop() + distanceMoved(event) <= ViewConfiguration.getTouchSlop() && + falsingManager?.isFalseTap(FalsingManager.NO_PENALTY) == false ) { dispatchClick(viewModel.configKey) } @@ -487,6 +502,7 @@ object KeyguardBottomAreaViewBinder { KeyguardQuickAffordanceViewModel.OnClickedParameters( configKey = configKey, expandable = Expandable.fromView(view), + slotId = viewModel.slotId, ) ) } @@ -553,6 +569,7 @@ object KeyguardBottomAreaViewBinder { KeyguardQuickAffordanceViewModel.OnClickedParameters( configKey = viewModel.configKey, expandable = Expandable.fromView(view), + slotId = viewModel.slotId, ) ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index ab9e6a4ce045..a8e346477690 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -175,7 +175,8 @@ constructor( areQuickAffordancesFullyOpaque, selectedPreviewSlotId, ) { model, animateReveal, isFullyOpaque, selectedPreviewSlotId -> - val isSelected = selectedPreviewSlotId == position.toSlotId() + val slotId = position.toSlotId() + val isSelected = selectedPreviewSlotId == slotId model.toViewModel( animateReveal = !previewMode.isInPreviewMode && animateReveal, isClickable = isFullyOpaque && !previewMode.isInPreviewMode, @@ -187,7 +188,8 @@ constructor( previewMode.isInPreviewMode && previewMode.shouldHighlightSelectedAffordance && !isSelected, - forceInactive = previewMode.isInPreviewMode + forceInactive = previewMode.isInPreviewMode, + slotId = slotId, ) } .distinctUntilChanged() @@ -200,6 +202,7 @@ constructor( isSelected: Boolean, isDimmed: Boolean, forceInactive: Boolean, + slotId: String, ): KeyguardQuickAffordanceViewModel { return when (this) { is KeyguardQuickAffordanceModel.Visible -> @@ -212,6 +215,7 @@ constructor( quickAffordanceInteractor.onQuickAffordanceTriggered( configKey = parameters.configKey, expandable = parameters.expandable, + slotId = parameters.slotId, ) }, isClickable = isClickable, @@ -219,8 +223,11 @@ constructor( isSelected = isSelected, useLongPress = quickAffordanceInteractor.useLongPress, isDimmed = isDimmed, + slotId = slotId, ) - is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel() + is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel( + slotId = slotId, + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt index cb68a82118e2..38d1db6d5768 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt @@ -32,9 +32,11 @@ data class KeyguardQuickAffordanceViewModel( val isSelected: Boolean = false, val useLongPress: Boolean = false, val isDimmed: Boolean = false, + val slotId: String, ) { data class OnClickedParameters( val configKey: String, val expandable: Expandable?, + val slotId: String, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt index 08907916a8c3..92038e24edf3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -21,6 +21,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.statusbar.SysuiStatusBarStateController import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.Flow @@ -34,6 +35,7 @@ class PrimaryBouncerToGoneTransitionViewModel @Inject constructor( private val interactor: KeyguardTransitionInteractor, + private val statusBarStateController: SysuiStatusBarStateController, ) { private val transitionAnimation = KeyguardTransitionAnimationFlow( @@ -41,6 +43,8 @@ constructor( transitionFlow = interactor.primaryBouncerToGoneTransition, ) + private var leaveShadeOpen: Boolean = false + /** Bouncer container alpha */ val bouncerAlpha: Flow<Float> = transitionAnimation.createFlow( @@ -48,11 +52,18 @@ constructor( onStep = { 1f - it }, ) - /** Scrim alpha */ - val scrimAlpha: Flow<Float> = + /** Scrim behind alpha */ + val scrimBehindAlpha: Flow<Float> = transitionAnimation.createFlow( duration = TO_GONE_DURATION, interpolator = EMPHASIZED_ACCELERATE, - onStep = { 1f - it }, + onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() }, + onStep = { + if (leaveShadeOpen) { + 1f + } else { + 1f - it + } + }, ) } 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 097cc3eef304..a31c1e566018 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 @@ -32,12 +32,15 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.ColorStateList; +import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; +import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.Animatable; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -63,7 +66,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import androidx.appcompat.content.res.AppCompatResources; import androidx.constraintlayout.widget.ConstraintSet; import com.android.internal.annotations.VisibleForTesting; @@ -146,6 +148,12 @@ public class MediaControlPanel { private static final int SMARTSPACE_CARD_CLICK_EVENT = 760; protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761; + private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f; + private static final float MEDIA_SCRIM_START_ALPHA = 0.25f; + private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f; + private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 0.9f; + private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f; + private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS); // Buttons to show in small player when using semantic actions @@ -779,7 +787,7 @@ public class MediaControlPanel { WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); if (wallpaperColors != null) { mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); - artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height); + artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, width, height); isArtworkBound = true; } else { // If there's no artwork, use colors from the app icon @@ -869,8 +877,9 @@ public class MediaControlPanel { Trace.beginAsyncSection(traceName, traceCookie); // Capture width & height from views in foreground for artwork scaling in background - int width = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredWidth(); - int height = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredHeight(); + int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width); + int height = mContext.getResources().getDimensionPixelSize( + R.dimen.qs_media_rec_album_height_expanded); mBackgroundExecutor.execute(() -> { // Album art @@ -880,7 +889,8 @@ public class MediaControlPanel { WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); if (wallpaperColors != null) { mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); - artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height); + artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width, + height); } else { artwork = new ColorDrawable(Color.TRANSPARENT); } @@ -889,6 +899,11 @@ public class MediaControlPanel { // Bind the artwork drawable to media cover. ImageView mediaCover = mRecommendationViewHolder.getMediaCoverItems().get(itemIndex); + // Rescale media cover + Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix()); + coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR, + 0.5f * width, 0.5f * height); + mediaCover.setImageMatrix(coverMatrix); mediaCover.setImageDrawable(artwork); // Set up the app icon. @@ -910,40 +925,62 @@ public class MediaControlPanel { // This method should be called from a background thread. WallpaperColors.fromBitmap takes a // good amount of time. We do that work on the background executor to avoid stalling animations // on the UI Thread. - private WallpaperColors getWallpaperColor(Icon artworkIcon) { + @VisibleForTesting + protected WallpaperColors getWallpaperColor(Icon artworkIcon) { if (artworkIcon != null) { if (artworkIcon.getType() == Icon.TYPE_BITMAP || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { // Avoids extra processing if this is already a valid bitmap - return WallpaperColors - .fromBitmap(artworkIcon.getBitmap()); + Bitmap artworkBitmap = artworkIcon.getBitmap(); + if (artworkBitmap.isRecycled()) { + Log.d(TAG, "Cannot load wallpaper color from a recycled bitmap"); + return null; + } + return WallpaperColors.fromBitmap(artworkBitmap); } else { Drawable artworkDrawable = artworkIcon.loadDrawable(mContext); if (artworkDrawable != null) { - return WallpaperColors - .fromDrawable(artworkIcon.loadDrawable(mContext)); + return WallpaperColors.fromDrawable(artworkDrawable); } } } return null; } - private LayerDrawable addGradientToIcon( - Icon artworkIcon, - ColorScheme mutableColorScheme, - int width, - int height - ) { + @VisibleForTesting + protected LayerDrawable addGradientToPlayerAlbum(Icon artworkIcon, + ColorScheme mutableColorScheme, int width, int height) { Drawable albumArt = getScaledBackground(artworkIcon, width, height); - GradientDrawable gradient = (GradientDrawable) AppCompatResources - .getDrawable(mContext, R.drawable.qs_media_scrim); + GradientDrawable gradient = (GradientDrawable) mContext.getDrawable( + R.drawable.qs_media_scrim).mutate(); + return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme, + MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA); + } + + @VisibleForTesting + protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon, + ColorScheme mutableColorScheme, int width, int height) { + // First try scaling rec card using bitmap drawable. + // If returns null, set drawable bounds. + Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height); + if (albumArt == null) { + albumArt = getScaledBackground(artworkIcon, width, height); + } + GradientDrawable gradient = (GradientDrawable) mContext.getDrawable( + R.drawable.qs_media_rec_scrim).mutate(); + return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme, + MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA); + } + + private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient, + ColorScheme mutableColorScheme, float startAlpha, float endAlpha) { gradient.setColors(new int[] { ColorUtilKt.getColorWithAlpha( MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme), - 0.25f), + startAlpha), ColorUtilKt.getColorWithAlpha( MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme), - 0.9f), + endAlpha), }); return new LayerDrawable(new Drawable[] { albumArt, gradient }); } @@ -1589,6 +1626,29 @@ public class MediaControlPanel { } /** + * Scale artwork to fill the background of media covers in recommendation card. + */ + @UiThread + private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) { + if (width == 0 || height == 0) { + return null; + } + if (artworkIcon != null) { + Bitmap bitmap; + if (artworkIcon.getType() == Icon.TYPE_BITMAP + || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { + Bitmap artworkBitmap = artworkIcon.getBitmap(); + if (artworkBitmap != null) { + bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width, + height, false); + return new BitmapDrawable(mContext.getResources(), bitmap); + } + } + } + return null; + } + + /** * Get the current media controller * * @return the controller diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java index e35575bfc184..b5b1f0ffe23d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java @@ -23,8 +23,6 @@ import android.util.Log; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.CommandQueue; import javax.inject.Inject; @@ -37,26 +35,19 @@ public class MediaOutputSwitcherDialogUI implements CoreStartable, CommandQueue. private final CommandQueue mCommandQueue; private final MediaOutputDialogFactory mMediaOutputDialogFactory; - private final FeatureFlags mFeatureFlags; @Inject public MediaOutputSwitcherDialogUI( Context context, CommandQueue commandQueue, - MediaOutputDialogFactory mediaOutputDialogFactory, - FeatureFlags featureFlags) { + MediaOutputDialogFactory mediaOutputDialogFactory) { mCommandQueue = commandQueue; mMediaOutputDialogFactory = mediaOutputDialogFactory; - mFeatureFlags = featureFlags; } @Override public void start() { - if (mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_SHOW_API_ENABLED)) { - mCommandQueue.addCallback(this); - } else { - Log.w(TAG, "Show media output switcher is not enabled."); - } + mCommandQueue.addCallback(this); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 4db1da3f1c95..006cedfe36b4 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -1007,7 +1007,11 @@ public class NavigationBar extends ViewController<NavigationBarView> implements private void notifyNavigationBarSurface() { ViewRootImpl viewRoot = mView.getViewRootImpl(); - SurfaceControl surface = viewRoot != null ? viewRoot.getSurfaceControl() : null; + SurfaceControl surface = viewRoot != null + && viewRoot.getSurfaceControl() != null + && viewRoot.getSurfaceControl().isValid() + ? viewRoot.getSurfaceControl() + : null; mOverviewProxyService.onNavigationBarSurfaceChanged(surface); } @@ -1729,41 +1733,26 @@ public class NavigationBar extends ViewController<NavigationBarView> implements bottomTappableProvider = new InsetsFrameProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT); } - if (!mEdgeBackGestureHandler.isHandlingGestures()) { - // 2/3 button navigation is on. Do not provide any gesture insets here. But need to keep - // the provider to support runtime update. - return new InsetsFrameProvider[] { - navBarProvider, - new InsetsFrameProvider( - ITYPE_BOTTOM_MANDATORY_GESTURES, Insets.NONE), - new InsetsFrameProvider(ITYPE_LEFT_GESTURES, InsetsFrameProvider.SOURCE_DISPLAY, - Insets.NONE, null), - new InsetsFrameProvider(ITYPE_RIGHT_GESTURES, - InsetsFrameProvider.SOURCE_DISPLAY, - Insets.NONE, null), - bottomTappableProvider - }; - } else { - // Gesture navigation - final int gestureHeight = userContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.navigation_bar_gesture_height); - final DisplayCutout cutout = userContext.getDisplay().getCutout(); - final int safeInsetsLeft = cutout != null ? cutout.getSafeInsetLeft() : 0; - final int safeInsetsRight = cutout != null ? cutout.getSafeInsetRight() : 0; - return new InsetsFrameProvider[] { - navBarProvider, - new InsetsFrameProvider( - ITYPE_BOTTOM_MANDATORY_GESTURES, Insets.of(0, 0, 0, gestureHeight)), - new InsetsFrameProvider(ITYPE_LEFT_GESTURES, InsetsFrameProvider.SOURCE_DISPLAY, - Insets.of(safeInsetsLeft - + mEdgeBackGestureHandler.getEdgeWidthLeft(), 0, 0, 0), null), - new InsetsFrameProvider(ITYPE_RIGHT_GESTURES, - InsetsFrameProvider.SOURCE_DISPLAY, - Insets.of(0, 0, safeInsetsRight - + mEdgeBackGestureHandler.getEdgeWidthRight(), 0), null), - bottomTappableProvider - }; - } + final DisplayCutout cutout = userContext.getDisplay().getCutout(); + final int safeInsetsLeft = cutout != null ? cutout.getSafeInsetLeft() : 0; + final int safeInsetsRight = cutout != null ? cutout.getSafeInsetRight() : 0; + final int gestureHeight = userContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_gesture_height); + final boolean handlingGesture = mEdgeBackGestureHandler.isHandlingGestures(); + final int gestureInsetsLeft = handlingGesture + ? mEdgeBackGestureHandler.getEdgeWidthLeft() + safeInsetsLeft : 0; + final int gestureInsetsRight = handlingGesture + ? mEdgeBackGestureHandler.getEdgeWidthRight() + safeInsetsRight : 0; + return new InsetsFrameProvider[] { + navBarProvider, + new InsetsFrameProvider( + ITYPE_BOTTOM_MANDATORY_GESTURES, Insets.of(0, 0, 0, gestureHeight)), + new InsetsFrameProvider(ITYPE_LEFT_GESTURES, InsetsFrameProvider.SOURCE_DISPLAY, + Insets.of(gestureInsetsLeft, 0, 0, 0), null), + new InsetsFrameProvider(ITYPE_RIGHT_GESTURES, InsetsFrameProvider.SOURCE_DISPLAY, + Insets.of(0, 0, gestureInsetsRight, 0), null), + bottomTappableProvider + }; } private boolean canShowSecondaryHandle() { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 342e0b006c18..f28c275158b9 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -28,6 +28,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; @@ -54,6 +55,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; import android.view.ViewConfiguration; +import android.view.WindowInsets; import android.view.WindowManager; import android.window.BackEvent; @@ -776,6 +778,19 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack return true; } + private boolean isValidTrackpadBackGesture(boolean isTrackpadEvent) { + if (!isTrackpadEvent) { + return false; + } + // for trackpad gestures, unless the whole screen is excluded region, 3-finger swipe + // gestures are allowed even if the cursor is in the excluded region. + WindowInsets windowInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets(); + Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars()); + final Rect excludeBounds = mExcludeRegion.getBounds(); + return !excludeBounds.contains(insets.left, insets.top, mDisplaySize.x - insets.right, + mDisplaySize.y - insets.bottom); + } + private boolean isWithinTouchRegion(int x, int y) { // If the point is inside the PiP or Nav bar overlay excluded bounds, then ignore the back // gesture @@ -896,7 +911,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack && (isTrackpadEvent || isWithinInsets) && !mGestureBlockingActivityRunning && !QuickStepContract.isBackGestureDisabled(mSysUiFlags) - && (isTrackpadEvent || isWithinTouchRegion((int) ev.getX(), (int) ev.getY())); + && (isValidTrackpadBackGesture(isTrackpadEvent) || isWithinTouchRegion( + (int) ev.getX(), (int) ev.getY())); if (mAllowGesture) { mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge); mEdgeBackPlugin.onMotionEvent(ev); diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index c65f0aaab91f..5b36e93ec5e1 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -22,6 +22,9 @@ import android.content.ActivityNotFoundException import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK +import android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.PackageManager import android.os.Build import android.os.UserManager @@ -54,8 +57,8 @@ constructor( private val resolver: NoteTaskInfoResolver, private val eventLogger: NoteTaskEventLogger, private val optionalBubbles: Optional<Bubbles>, - private val optionalUserManager: Optional<UserManager>, - private val optionalKeyguardManager: Optional<KeyguardManager>, + private val userManager: UserManager, + private val keyguardManager: KeyguardManager, @NoteTaskEnabledKey private val isEnabled: Boolean, private val devicePolicyManager: DevicePolicyManager, private val userTracker: UserTracker, @@ -106,8 +109,6 @@ constructor( if (!isEnabled) return val bubbles = optionalBubbles.getOrNull() ?: return - val userManager = optionalUserManager.getOrNull() ?: return - val keyguardManager = optionalKeyguardManager.getOrNull() ?: return // TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing. if (!userManager.isUserUnlocked) return @@ -140,12 +141,13 @@ constructor( logDebug { "onShowNoteTask - start: $info" } when (info.launchMode) { is NoteTaskLaunchMode.AppBubble -> { + // TODO(b/267634412, b/268351693): Should use `showOrHideAppBubbleAsUser` bubbles.showOrHideAppBubble(intent) // App bubble logging happens on `onBubbleExpandChanged`. logDebug { "onShowNoteTask - opened as app bubble: $info" } } is NoteTaskLaunchMode.Activity -> { - context.startActivity(intent) + context.startActivityAsUser(intent, userTracker.userHandle) eventLogger.logNoteTaskOpened(info) logDebug { "onShowNoteTask - opened as activity: $info" } } @@ -198,12 +200,21 @@ constructor( } private fun createNoteIntent(info: NoteTaskInfo): Intent = - Intent(NoteTaskController.ACTION_CREATE_NOTE) - .setPackage(info.packageName) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + Intent(NoteTaskController.ACTION_CREATE_NOTE).apply { + setPackage(info.packageName) + // EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint // was used to start it. - .putExtra(NoteTaskController.INTENT_EXTRA_USE_STYLUS_MODE, true) + putExtra(NoteTaskController.INTENT_EXTRA_USE_STYLUS_MODE, true) + + addFlags(FLAG_ACTIVITY_NEW_TASK) + // We should ensure the note experience can be open both as a full screen (lock screen) + // and inside the app bubble (contextual). These additional flags will do that. + if (info.launchMode == NoteTaskLaunchMode.Activity) { + addFlags(FLAG_ACTIVITY_MULTIPLE_TASK) + addFlags(FLAG_ACTIVITY_NEW_DOCUMENT) + } + } private inline fun logDebug(message: () -> String) { if (Build.IS_DEBUGGABLE) { diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt index acc537a8eb36..2fa8f9a1e6fc 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt @@ -17,7 +17,7 @@ package com.android.systemui.notetask import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceConfig import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity -import com.android.systemui.screenshot.AppClipsTrampolineActivity +import com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity /** * Supported entry points for [NoteTaskController.showNoteTask]. diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt index 0f75f9591074..7be491f0b3a6 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt @@ -17,19 +17,19 @@ package com.android.systemui.notetask import android.app.role.RoleManager -import android.content.Context import android.content.pm.PackageManager import android.content.pm.PackageManager.ApplicationInfoFlags import android.os.UserHandle import android.util.Log +import com.android.systemui.settings.UserTracker import javax.inject.Inject class NoteTaskInfoResolver @Inject constructor( - private val context: Context, private val roleManager: RoleManager, private val packageManager: PackageManager, + private val userTracker: UserTracker, ) { fun resolveInfo( @@ -38,7 +38,7 @@ constructor( isKeyguardLocked: Boolean = false, ): NoteTaskInfo? { // TODO(b/267634412): Select UserHandle depending on where the user initiated note-taking. - val user = context.user + val user = userTracker.userHandle val packageName = roleManager.getRoleHoldersAsUser(RoleManager.ROLE_NOTES, user).firstOrNull() diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt index ba8999c068e3..6278c699498c 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt @@ -17,11 +17,7 @@ package com.android.systemui.notetask import android.app.Activity -import android.app.KeyguardManager import android.app.role.RoleManager -import android.content.Context -import android.os.UserManager -import androidx.core.content.getSystemService import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceModule @@ -32,7 +28,6 @@ import dagger.Module import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap -import java.util.Optional /** Compose all dependencies required by Note Task feature. */ @Module(includes = [NoteTaskQuickAffordanceModule::class]) @@ -55,15 +50,5 @@ interface NoteTaskModule { val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS) return isRoleAvailable && isFeatureEnabled } - - @Provides - fun provideOptionalKeyguardManager(context: Context): Optional<KeyguardManager> { - return Optional.ofNullable(context.getSystemService()) - } - - @Provides - fun provideOptionalUserManager(context: Context): Optional<UserManager> { - return Optional.ofNullable(context.getSystemService()) - } } } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/OWNERS b/packages/SystemUI/src/com/android/systemui/notetask/OWNERS index 7ccb316dbca5..0ec996be72de 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/notetask/OWNERS @@ -5,4 +5,6 @@ juliacr@google.com madym@google.com mgalhardo@google.com petrcermak@google.com +stevenckng@google.com +tkachenkoi@google.com vanjan@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt index 8ced46461dbb..5c59532e0c2e 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt @@ -17,8 +17,10 @@ package com.android.systemui.notetask.shortcut import android.app.Activity +import android.app.role.RoleManager import android.content.Intent import android.os.Bundle +import android.os.PersistableBundle import androidx.activity.ComponentActivity import androidx.annotation.DrawableRes import androidx.core.content.pm.ShortcutInfoCompat @@ -36,7 +38,11 @@ import javax.inject.Inject * href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating * a custom shortcut activity</a> */ -class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentActivity() { +class CreateNoteTaskShortcutActivity +@Inject +constructor( + private val roleManager: RoleManager, +) : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -59,12 +65,19 @@ class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentActivity() intent: Intent, @DrawableRes iconResource: Int, ): Intent { + val extras = PersistableBundle() + + roleManager.getRoleHoldersAsUser(RoleManager.ROLE_NOTES, user).firstOrNull()?.let { name -> + extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, name) + } + val shortcutInfo = ShortcutInfoCompat.Builder(this, id) .setIntent(intent) .setShortLabel(shortLabel) .setLongLived(true) .setIcon(IconCompat.createWithResource(this, iconResource)) + .setExtras(extras) .build() return ShortcutManagerCompat.createShortcutResultIntent( @@ -75,5 +88,16 @@ class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentActivity() private companion object { private const val SHORTCUT_ID = "note-task-shortcut-id" + + /** + * Shortcut extra which can point to a package name and can be used to indicate an alternate + * badge info. Launcher only reads this if the shortcut comes from a system app. + * + * Duplicated from [com.android.launcher3.icons.IconCache]. + * + * @see com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE + */ + private const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE = + "extra_shortcut_badge_override_package" } } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index 2522e1c5b798..7a42642f2667 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -154,6 +154,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY); private final Intent mOpenBatterySaverSettings = settings(Settings.ACTION_BATTERY_SAVER_SETTINGS); + private final boolean mUseExtraSaverConfirmation; private int mBatteryLevel; private int mBucket; @@ -197,6 +198,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mDialogLaunchAnimator = dialogLaunchAnimator; mUiEventLogger = uiEventLogger; mUserTracker = userTracker; + mUseExtraSaverConfirmation = + mContext.getResources().getBoolean(R.bool.config_extra_battery_saver_confirmation); } @Override @@ -644,7 +647,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private void showStartSaverConfirmation(Bundle extras) { - if (mSaverConfirmation != null) return; + if (mSaverConfirmation != null || mUseExtraSaverConfirmation) return; final SystemUIDialog d = new SystemUIDialog(mContext); final boolean confirmOnly = extras.getBoolean(BatterySaverUtils.EXTRA_CONFIRM_TEXT_ONLY); final int batterySaverTriggerMode = @@ -679,6 +682,10 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { resolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1, mUserTracker.getUserId()); + Secure.putIntForUser( + resolver, + Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, + 1, mUserTracker.getUserId()); }); } else { d.setTitle(R.string.battery_saver_confirmation_title); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index e86bd7a30490..9f93e4926532 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -76,7 +76,8 @@ public class TileServiceManager { this(tileServices, handler, userTracker, new TileLifecycleManager(handler, tileServices.getContext(), tileServices, new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher, - new Intent().setComponent(component), userTracker.getUserHandle())); + new Intent(TileService.ACTION_QS_TILE).setComponent(component), + userTracker.getUserHandle())); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 25ff308b46bb..019ca52107dd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -631,7 +631,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis final NavigationBarView navBarView = mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId()); final NotificationPanelViewController panelController = - mCentralSurfacesOptionalLazy.get().get().getNotificationPanelViewController(); + mCentralSurfacesOptionalLazy.get() + .map(CentralSurfaces::getNotificationPanelViewController) + .orElse(null); if (SysUiState.DEBUG) { Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment + " navBarView=" + navBarView + " panelController=" + panelController); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java index c8c133774766..7cfe2327f992 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java @@ -57,7 +57,8 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -class ImageExporter { +/** A class to help with exporting screenshot to storage. */ +public class ImageExporter { private static final String TAG = LogConfig.logTag(ImageExporter.class); static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24); @@ -90,7 +91,7 @@ class ImageExporter { private final FeatureFlags mFlags; @Inject - ImageExporter(ContentResolver resolver, FeatureFlags flags) { + public ImageExporter(ContentResolver resolver, FeatureFlags flags) { mResolver = resolver; mFlags = flags; } @@ -148,7 +149,7 @@ class ImageExporter { * * @return a listenable future result */ - ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap, + public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap, UserHandle owner) { return export(executor, requestId, bitmap, ZonedDateTime.now(), owner); } @@ -181,13 +182,14 @@ class ImageExporter { ); } - static class Result { - Uri uri; - UUID requestId; - String fileName; - long timestamp; - CompressFormat format; - boolean published; + /** The result returned by the task exporting screenshots to storage. */ + public static class Result { + public Uri uri; + public UUID requestId; + public String fileName; + public long timestamp; + public CompressFormat format; + public boolean published; @Override public String toString() { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java index fc94aed5336a..7a62bae5b5ae 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java @@ -93,13 +93,7 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "User has discarded the result of a long screenshot") SCREENSHOT_LONG_SCREENSHOT_EXIT(911), @UiEvent(doc = "A screenshot has been taken and saved to work profile") - SCREENSHOT_SAVED_TO_WORK_PROFILE(1240), - @UiEvent(doc = "Notes application triggered the screenshot for notes") - SCREENSHOT_FOR_NOTE_TRIGGERED(1308), - @UiEvent(doc = "User accepted the screenshot to be sent to the notes app") - SCREENSHOT_FOR_NOTE_ACCEPTED(1309), - @UiEvent(doc = "User cancelled the screenshot for notes app flow") - SCREENSHOT_FOR_NOTE_CANCELLED(1310); + SCREENSHOT_SAVED_TO_WORK_PROFILE(1240); private final int mId; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java index 3133924339f2..4756cc8172e9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package com.android.systemui.screenshot; +package com.android.systemui.screenshot.appclips; -import static com.android.systemui.screenshot.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE; -import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME; -import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER; -import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI; -import static com.android.systemui.screenshot.AppClipsTrampolineActivity.PERMISSION_SELF; -import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED; -import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED; +import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_ACCEPTED; +import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_CANCELLED; +import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE; +import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME; +import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER; +import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI; +import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.PERMISSION_SELF; import android.app.Activity; import android.content.BroadcastReceiver; @@ -52,6 +52,8 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLogger.UiEventEnum; import com.android.settingslib.Utils; import com.android.systemui.R; +import com.android.systemui.screenshot.CropView; +import com.android.systemui.screenshot.MagnifierView; import com.android.systemui.settings.UserTracker; import javax.inject.Inject; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java index 65fb4c9bfb0d..e1619dc9b6ee 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java @@ -32,12 +32,12 @@ import javax.inject.Inject; /** An intermediary singleton object to help communicating with the cross process service. */ @SysUISingleton -public class AppClipsCrossProcessHelper { +class AppClipsCrossProcessHelper { private final ServiceConnector<IAppClipsScreenshotHelperService> mProxyConnector; @Inject - public AppClipsCrossProcessHelper(@Application Context context) { + AppClipsCrossProcessHelper(@Application Context context) { mProxyConnector = new ServiceConnector.Impl<IAppClipsScreenshotHelperService>(context, new Intent(context, AppClipsScreenshotHelperService.class), Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY @@ -52,7 +52,7 @@ public class AppClipsCrossProcessHelper { * pass around but not a {@link Bitmap}. */ @Nullable - public Bitmap takeScreenshot() { + Bitmap takeScreenshot() { try { AndroidFuture<ScreenshotHardwareBufferInternal> future = mProxyConnector.postForResult( diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsEvent.java new file mode 100644 index 000000000000..7a085b9fd7d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsEvent.java @@ -0,0 +1,40 @@ +/* + * 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.screenshot.appclips; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; + +enum AppClipsEvent implements UiEventLogger.UiEventEnum { + + @UiEvent(doc = "Notes application triggered the screenshot for notes") + SCREENSHOT_FOR_NOTE_TRIGGERED(1308), + @UiEvent(doc = "User accepted the screenshot to be sent to the notes app") + SCREENSHOT_FOR_NOTE_ACCEPTED(1309), + @UiEvent(doc = "User cancelled the screenshot for notes app flow") + SCREENSHOT_FOR_NOTE_CANCELLED(1310); + + private final int mId; + + AppClipsEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java index 6f8c36595c74..83ff020362f1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java @@ -24,7 +24,6 @@ import android.window.ScreenCapture.ScreenshotSync; import androidx.annotation.Nullable; -import com.android.systemui.screenshot.AppClipsActivity; import com.android.wm.shell.bubbles.Bubbles; import java.util.Optional; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java index eda38e45c98a..3cb1a34a921c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.screenshot; +package com.android.systemui.screenshot.appclips; import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN; import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED; @@ -24,7 +24,7 @@ import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE; import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS; -import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED; +import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED; import android.app.Activity; import android.app.admin.DevicePolicyManager; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java index b2910fd48854..4cbca28a4032 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java @@ -14,12 +14,10 @@ * limitations under the License. */ -package com.android.systemui.screenshot; +package com.android.systemui.screenshot.appclips; import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED; -import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE; - import android.content.Intent; import android.graphics.Bitmap; import android.graphics.HardwareRenderer; @@ -31,7 +29,6 @@ import android.net.Uri; import android.os.Process; import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; @@ -39,11 +36,10 @@ import androidx.lifecycle.ViewModelProvider; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.screenshot.appclips.AppClipsCrossProcessHelper; +import com.android.systemui.screenshot.ImageExporter; import com.google.common.util.concurrent.ListenableFuture; -import java.time.ZonedDateTime; import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -52,8 +48,7 @@ import java.util.concurrent.Executor; import javax.inject.Inject; /** A {@link ViewModel} to help with the App Clips screenshot flow. */ -@VisibleForTesting(otherwise = PACKAGE_PRIVATE) -public final class AppClipsViewModel extends ViewModel { +final class AppClipsViewModel extends ViewModel { private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper; private final ImageExporter mImageExporter; @@ -80,8 +75,7 @@ public final class AppClipsViewModel extends ViewModel { } /** Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link LiveData}. */ - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - public void performScreenshot() { + void performScreenshot() { mBgExecutor.execute(() -> { Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot(); mMainExecutor.execute(() -> { @@ -95,14 +89,12 @@ public final class AppClipsViewModel extends ViewModel { } /** Returns a {@link LiveData} that holds the captured screenshot. */ - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - public LiveData<Bitmap> getScreenshot() { + LiveData<Bitmap> getScreenshot() { return mScreenshotLiveData; } /** Returns a {@link LiveData} that holds the {@link Uri} where screenshot is saved. */ - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - public LiveData<Uri> getResultLiveData() { + LiveData<Uri> getResultLiveData() { return mResultLiveData; } @@ -110,8 +102,7 @@ public final class AppClipsViewModel extends ViewModel { * Returns a {@link LiveData} that holds the error codes for * {@link Intent#EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE}. */ - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - public LiveData<Integer> getErrorLiveData() { + LiveData<Integer> getErrorLiveData() { return mErrorLiveData; } @@ -119,8 +110,7 @@ public final class AppClipsViewModel extends ViewModel { * Saves the provided {@link Drawable} to storage then informs the result {@link Uri} to * {@link LiveData}. */ - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - public void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) { + void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) { mBgExecutor.execute(() -> { // Render the screenshot bitmap in background. Bitmap screenshotBitmap = renderBitmap(screenshotDrawable, bounds); @@ -128,7 +118,7 @@ public final class AppClipsViewModel extends ViewModel { // Export and save the screenshot in background. // TODO(b/267310185): Save to work profile UserHandle. ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export( - mBgExecutor, UUID.randomUUID(), screenshotBitmap, ZonedDateTime.now(), + mBgExecutor, UUID.randomUUID(), screenshotBitmap, Process.myUserHandle()); // Get the result and update state on main thread. @@ -160,8 +150,7 @@ public final class AppClipsViewModel extends ViewModel { } /** Helper factory to help with injecting {@link AppClipsViewModel}. */ - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - public static final class Factory implements ViewModelProvider.Factory { + static final class Factory implements ViewModelProvider.Factory { private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper; private final ImageExporter mImageExporter; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/ScreenshotHardwareBufferInternal.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/ScreenshotHardwareBufferInternal.java index 3b107f101088..1e53ebb7935e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/ScreenshotHardwareBufferInternal.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/ScreenshotHardwareBufferInternal.java @@ -28,7 +28,7 @@ import android.window.ScreenCapture.ScreenshotHardwareBuffer; * An internal version of {@link ScreenshotHardwareBuffer} that helps with parceling the information * necessary for creating a {@link Bitmap}. */ -public class ScreenshotHardwareBufferInternal implements Parcelable { +class ScreenshotHardwareBufferInternal implements Parcelable { public static final Creator<ScreenshotHardwareBufferInternal> CREATOR = new Creator<>() { @@ -45,7 +45,7 @@ public class ScreenshotHardwareBufferInternal implements Parcelable { private final HardwareBuffer mHardwareBuffer; private final ParcelableColorSpace mParcelableColorSpace; - public ScreenshotHardwareBufferInternal( + ScreenshotHardwareBufferInternal( ScreenshotHardwareBuffer screenshotHardwareBuffer) { mHardwareBuffer = screenshotHardwareBuffer.getHardwareBuffer(); mParcelableColorSpace = new ParcelableColorSpace( @@ -65,7 +65,7 @@ public class ScreenshotHardwareBufferInternal implements Parcelable { * {@link Bitmap#wrapHardwareBuffer(HardwareBuffer, ColorSpace)} and * {@link HardwareBuffer#close()} for more information. */ - public Bitmap createBitmapThenCloseBuffer() { + Bitmap createBitmapThenCloseBuffer() { Bitmap bitmap = Bitmap.wrapHardwareBuffer(mHardwareBuffer, mParcelableColorSpace.getColorSpace()); mHardwareBuffer.close(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index f0d064b42d9c..9a9503c8cd9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -572,8 +572,7 @@ class LockscreenShadeTransitionController @Inject constructor( entry.setGroupExpansionChanging(true) userId = entry.sbn.userId } - var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic( - lockScreenUserManager.getCurrentUserId()) || + var fullShadeNeedsBouncer = ( !lockScreenUserManager.shouldShowLockscreenNotifications() || falsingCollector.shouldEnforceBouncer()) if (keyguardBypassController.bypassEnabled) { 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 7855cdfeb4c3..cf5ecdddf854 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -389,6 +389,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean isStrongBiometric) { Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated"); if (mUpdateMonitor.isGoingToSleep()) { + mLogger.deferringAuthenticationDueToSleep(userId, + biometricSourceType, + mPendingAuthenticated != null); mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType, isStrongBiometric); Trace.endSection(); @@ -795,6 +798,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp public void onFinishedGoingToSleep() { Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep"); if (mPendingAuthenticated != null) { + mLogger.finishedGoingToSleepWithPendingAuth(); PendingAuthenticated pendingAuthenticated = mPendingAuthenticated; // Post this to make sure it's executed after the device is fully locked. mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index b88531e59568..ae715b3f20c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -429,7 +429,6 @@ public class DozeParameters implements } dispatchAlwaysOnEvent(); - mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn()); } @Override @@ -469,6 +468,7 @@ public class DozeParameters implements for (Callback callback : mCallbacks) { callback.onAlwaysOnChange(); } + mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn()); } private boolean getPostureSpecificBool( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index 753032c2ee01..3268032becf8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -59,7 +59,7 @@ import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt; -import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator; +import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -75,6 +75,8 @@ import java.util.concurrent.Executor; import javax.inject.Inject; +import kotlin.Unit; + /** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */ public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> { private static final String TAG = "KeyguardStatusBarViewController"; @@ -123,7 +125,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat public void onDensityOrFontScaleChanged() { mView.loadDimens(); // The animator is dependent on resources for offsets - mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources()); + mSystemEventAnimator = + getSystemEventAnimator(mSystemEventAnimator.isAnimationRunning()); } @Override @@ -248,7 +251,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private int mStatusBarState; private boolean mDozing; private boolean mShowingKeyguardHeadsUp; - private StatusBarSystemEventAnimator mSystemEventAnimator; + private StatusBarSystemEventDefaultAnimator mSystemEventAnimator; + private float mSystemEventAnimatorAlpha = 1; /** * The alpha value to be set on the View. If -1, this value is to be ignored. @@ -324,7 +328,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat mView.setKeyguardUserAvatarEnabled( !mStatusBarUserChipViewModel.getChipEnabled()); - mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r); + mSystemEventAnimator = getSystemEventAnimator(/* isAnimationRunning */ false); mDisableStateTracker = new DisableStateTracker( /* mask1= */ DISABLE_SYSTEM_INFO, @@ -480,6 +484,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat * (1.0f - mKeyguardHeadsUpShowingAmount); } + if (mSystemEventAnimator.isAnimationRunning()) { + newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha); + } + boolean hideForBypass = mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace() || mDelayShowingKeyguardStatusBar; @@ -488,7 +496,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat && !mDozing && !hideForBypass && !mDisableStateTracker.isDisabled() - ? View.VISIBLE : View.INVISIBLE; + ? View.VISIBLE : View.INVISIBLE; updateViewState(newAlpha, newVisibility); } @@ -614,4 +622,15 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat updateBlockedIcons(); } }; + + private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) { + return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> { + mSystemEventAnimatorAlpha = alpha; + updateViewState(); + return Unit.INSTANCE; + }, (translationX) -> { + mView.setTranslationX(translationX); + return Unit.INSTANCE; + }, isAnimationRunning); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index ce650d557dd3..9fb942c7b740 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -62,6 +62,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.scrim.ScrimView; import com.android.systemui.shade.NotificationPanelViewController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -205,6 +206,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private final ScreenOffAnimationController mScreenOffAnimationController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final SysuiStatusBarStateController mStatusBarStateController; private GradientColors mColors; private boolean mNeedsDrawableColorUpdate; @@ -261,25 +263,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private KeyguardTransitionInteractor mKeyguardTransitionInteractor; private CoroutineDispatcher mMainDispatcher; - private boolean mIsBouncerToGoneTransitionStarted = false; private boolean mIsBouncerToGoneTransitionRunning = false; private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; private final Consumer<Float> mScrimAlphaConsumer = (Float alpha) -> { - mScrimInFront.setViewAlpha(0f); - mNotificationsScrim.setViewAlpha(0f); + mScrimInFront.setViewAlpha(mInFrontAlpha); + mNotificationsScrim.setViewAlpha(mNotificationsAlpha); + mBehindAlpha = alpha; mScrimBehind.setViewAlpha(alpha); }; - final Consumer<TransitionStep> mPrimaryBouncerToGoneTransition = - (TransitionStep step) -> { - mIsBouncerToGoneTransitionRunning = - step.getTransitionState() == TransitionState.RUNNING; - mIsBouncerToGoneTransitionStarted = - step.getTransitionState() == TransitionState.STARTED; - if (mIsBouncerToGoneTransitionStarted) { - transitionTo(ScrimState.UNLOCKED); - } - }; + + Consumer<TransitionStep> mPrimaryBouncerToGoneTransition; @Inject public ScrimController( @@ -298,6 +292,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump StatusBarKeyguardViewManager statusBarKeyguardViewManager, PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel, KeyguardTransitionInteractor keyguardTransitionInteractor, + SysuiStatusBarStateController sysuiStatusBarStateController, @Main CoroutineDispatcher mainDispatcher) { mScrimStateListener = lightBarController::setScrimState; mDefaultScrimAlpha = BUSY_SCRIM_ALPHA; @@ -305,6 +300,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mKeyguardStateController = keyguardStateController; mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen(); mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mStatusBarStateController = sysuiStatusBarStateController; mKeyguardVisibilityCallback = new KeyguardVisibilityCallback(); mHandler = handler; mMainExecutor = mainExecutor; @@ -380,9 +376,31 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump state.prepare(state); } + // Directly control transition to UNLOCKED scrim state from PRIMARY_BOUNCER, and make sure + // to report back that keyguard has faded away. This fixes cases where the scrim state was + // rapidly switching on unlock, due to shifts in state in CentralSurfacesImpl + mPrimaryBouncerToGoneTransition = + (TransitionStep step) -> { + TransitionState state = step.getTransitionState(); + + mIsBouncerToGoneTransitionRunning = state == TransitionState.RUNNING; + + if (state == TransitionState.STARTED) { + setExpansionAffectsAlpha(false); + transitionTo(ScrimState.UNLOCKED); + } + + if (state == TransitionState.FINISHED || state == TransitionState.CANCELED) { + setExpansionAffectsAlpha(true); + if (mKeyguardStateController.isKeyguardFadingAway()) { + mStatusBarKeyguardViewManager.onKeyguardFadedAway(); + } + } + }; + collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(), mPrimaryBouncerToGoneTransition, mMainDispatcher); - collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(), + collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha(), mScrimAlphaConsumer, mMainDispatcher); } @@ -843,11 +861,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mBehindAlpha = 0; mNotificationsAlpha = 0; } else { + // Behind scrim will finish fading in at 30% expansion. float behindFraction = MathUtils .constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction); - if (!mIsBouncerToGoneTransitionStarted) { - mBehindAlpha = behindFraction * mDefaultScrimAlpha; - } + mBehindAlpha = behindFraction * mDefaultScrimAlpha; // Delay fade-in of notification scrim a bit further, to coincide with the // behind scrim finishing fading in. // Also to coincide with the view starting to fade in, otherwise the empty @@ -1096,7 +1113,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mBehindAlpha = 1; } // Prevent notification scrim flicker when transitioning away from keyguard. - if (mKeyguardStateController.isKeyguardGoingAway()) { + if (mKeyguardStateController.isKeyguardGoingAway() + && !mStatusBarStateController.leaveOpenOnKeyguardHide()) { mNotificationsAlpha = 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 726b2344309f..edfc95fcc2e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -16,11 +16,13 @@ package com.android.systemui.statusbar.phone; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.service.notification.NotificationListenerService.REASON_CLICK; import static com.android.systemui.statusbar.phone.CentralSurfaces.getActivityOptions; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.app.KeyguardManager; import android.app.Notification; import android.app.PendingIntent; @@ -579,8 +581,14 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, entry.getKey()); mCentralSurfaces.wakeUpForFullScreenIntent(); - fullScreenIntent.send(); + + ActivityOptions options = ActivityOptions.makeBasic(); + options.setPendingIntentBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_ALLOWED); + fullScreenIntent.sendAndReturnResult(null, 0, null, null, null, null, + options.toBundle()); entry.notifyFullScreenIntentLaunched(); + mMetricsLogger.count("note_fullscreen", 1); String activityName; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt index c04ea36b3d8d..5903fa3d5bd1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt @@ -26,19 +26,39 @@ import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT import com.android.systemui.statusbar.events.SystemStatusAnimationCallback import com.android.systemui.util.animation.AnimationUtil.Companion.frames +import com.android.systemui.util.doOnCancel +import com.android.systemui.util.doOnEnd + +/** + * An implementation of [StatusBarSystemEventDefaultAnimator], applying the onAlphaChanged and + * onTranslationXChanged callbacks directly to the provided animatedView. + */ +class StatusBarSystemEventAnimator @JvmOverloads constructor( + val animatedView: View, + resources: Resources, + isAnimationRunning: Boolean = false +) : StatusBarSystemEventDefaultAnimator( + resources = resources, + onAlphaChanged = animatedView::setAlpha, + onTranslationXChanged = animatedView::setTranslationX, + isAnimationRunning = isAnimationRunning +) /** * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed - * status bar fragment), can just feed this an animatable view to get the default system status - * animation. + * status bar fragment), can use this Animator to get the default system status animation. It simply + * needs to implement the onAlphaChanged and onTranslationXChanged callbacks. * * This animator relies on resources, and should be recreated whenever resources are updated. While * this class could be used directly as the animation callback, it's probably best to forward calls * to it so that it can be recreated at any moment without needing to remove/add callback. */ -class StatusBarSystemEventAnimator( - val animatedView: View, - resources: Resources + +open class StatusBarSystemEventDefaultAnimator @JvmOverloads constructor( + resources: Resources, + private val onAlphaChanged: (Float) -> Unit, + private val onTranslationXChanged: (Float) -> Unit, + var isAnimationRunning: Boolean = false ) : SystemStatusAnimationCallback { private val translationXIn: Int = resources.getDimensionPixelSize( R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x) @@ -46,18 +66,19 @@ class StatusBarSystemEventAnimator( R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x) override fun onSystemEventAnimationBegin(): Animator { + isAnimationRunning = true val moveOut = ValueAnimator.ofFloat(0f, 1f).apply { duration = 23.frames interpolator = STATUS_BAR_X_MOVE_OUT addUpdateListener { - animatedView.translationX = -(translationXIn * animatedValue as Float) + onTranslationXChanged(-(translationXIn * animatedValue as Float)) } } val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply { duration = 8.frames interpolator = null addUpdateListener { - animatedView.alpha = animatedValue as Float + onAlphaChanged(animatedValue as Float) } } @@ -67,13 +88,13 @@ class StatusBarSystemEventAnimator( } override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator { - animatedView.translationX = translationXOut.toFloat() + onTranslationXChanged(translationXOut.toFloat()) val moveIn = ValueAnimator.ofFloat(1f, 0f).apply { duration = 23.frames startDelay = 7.frames interpolator = STATUS_BAR_X_MOVE_IN addUpdateListener { - animatedView.translationX = translationXOut * animatedValue as Float + onTranslationXChanged(translationXOut * animatedValue as Float) } } val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply { @@ -81,13 +102,14 @@ class StatusBarSystemEventAnimator( startDelay = 11.frames interpolator = null addUpdateListener { - animatedView.alpha = animatedValue as Float + onAlphaChanged(animatedValue as Float) } } val animatorSet = AnimatorSet() animatorSet.playTogether(moveIn, alphaIn) - + animatorSet.doOnEnd { isAnimationRunning = false } + animatorSet.doOnCancel { isAnimationRunning = false } return animatorSet } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/stylus/OWNERS b/packages/SystemUI/src/com/android/systemui/stylus/OWNERS index 7ccb316dbca5..0ec996be72de 100644 --- a/packages/SystemUI/src/com/android/systemui/stylus/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/stylus/OWNERS @@ -5,4 +5,6 @@ juliacr@google.com madym@google.com mgalhardo@google.com petrcermak@google.com +stevenckng@google.com +tkachenkoi@google.com vanjan@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt index 4e27ce6721d7..9952cfd4e85b 100644 --- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt @@ -22,6 +22,7 @@ import android.content.Context import android.hardware.BatteryState import android.hardware.input.InputManager import android.hardware.input.InputSettings +import android.os.Build import android.os.Handler import android.util.ArrayMap import android.util.Log @@ -61,8 +62,6 @@ constructor( BluetoothAdapter.OnMetadataChangedListener { private val stylusCallbacks: CopyOnWriteArrayList<StylusCallback> = CopyOnWriteArrayList() - private val stylusBatteryCallbacks: CopyOnWriteArrayList<StylusBatteryCallback> = - CopyOnWriteArrayList() // This map should only be accessed on the handler private val inputDeviceAddressMap: MutableMap<Int, String?> = ArrayMap() @@ -105,14 +104,6 @@ constructor( stylusCallbacks.remove(callback) } - fun registerBatteryCallback(callback: StylusBatteryCallback) { - stylusBatteryCallbacks.add(callback) - } - - fun unregisterBatteryCallback(callback: StylusBatteryCallback) { - stylusBatteryCallbacks.remove(callback) - } - override fun onInputDeviceAdded(deviceId: Int) { if (!hasStarted) return @@ -194,7 +185,7 @@ constructor( "${device.address}: $isCharging" } - executeStylusBatteryCallbacks { cb -> + executeStylusCallbacks { cb -> cb.onStylusBluetoothChargingStateChanged(inputDeviceId, device, isCharging) } } @@ -220,7 +211,7 @@ constructor( onStylusUsed() } - executeStylusBatteryCallbacks { cb -> + executeStylusCallbacks { cb -> cb.onStylusUsiBatteryStateChanged(deviceId, eventTimeMillis, batteryState) } } @@ -328,10 +319,6 @@ constructor( stylusCallbacks.forEach(run) } - private fun executeStylusBatteryCallbacks(run: (cb: StylusBatteryCallback) -> Unit) { - stylusBatteryCallbacks.forEach(run) - } - private fun registerBatteryListener(deviceId: Int) { try { inputManager.addInputDeviceBatteryListener(deviceId, executor, this) @@ -377,13 +364,6 @@ constructor( fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {} fun onStylusBluetoothDisconnected(deviceId: Int, btAddress: String) {} fun onStylusFirstUsed() {} - } - - /** - * Callback interface to receive stylus battery events from the StylusManager. All callbacks are - * runs on the same background handler. - */ - interface StylusBatteryCallback { fun onStylusBluetoothChargingStateChanged( inputDeviceId: Int, btDevice: BluetoothDevice, @@ -398,12 +378,11 @@ constructor( companion object { val TAG = StylusManager::class.simpleName.orEmpty() - const val DEBUG = false } } private inline fun logDebug(message: () -> String) { - if (StylusManager.DEBUG) { + if (Build.IS_DEBUGGABLE) { Log.d(StylusManager.TAG, message()) } } diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt index 27cafb10c07d..3667392b515e 100644 --- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt @@ -37,7 +37,7 @@ constructor( private val inputManager: InputManager, private val stylusUsiPowerUi: StylusUsiPowerUI, private val featureFlags: FeatureFlags, -) : CoreStartable, StylusManager.StylusCallback, StylusManager.StylusBatteryCallback { +) : CoreStartable, StylusManager.StylusCallback { override fun onStylusAdded(deviceId: Int) { // On some devices, the addition of a new internal stylus indicates the use of a @@ -74,7 +74,6 @@ constructor( stylusUsiPowerUi.init() stylusManager.registerCallback(this) - stylusManager.registerBatteryCallback(this) stylusManager.startListener() } diff --git a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt index e092f01d19f6..8e2b05cd9526 100644 --- a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt @@ -66,7 +66,7 @@ class SwitchToManagedProfileForCallActivity : AlertActivity(), DialogInterface.O private fun switchToManagedProfile() { try { applicationContext.startActivityAsUser( - Intent(Intent.ACTION_DIAL, phoneNumber), + Intent(Intent.ACTION_CALL, phoneNumber), ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(), UserHandle.of(managedProfileUserId) ) diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java index d5d3efd78d13..3a7ac9c8a8bd 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java @@ -31,6 +31,9 @@ import android.view.WindowManager; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; + +import javax.inject.Inject; /** * If the attached USB accessory has a URL associated with it, and that URL is valid, @@ -46,13 +49,27 @@ public class UsbAccessoryUriActivity extends AlertActivity private UsbAccessory mAccessory; private Uri mUri; + private final DeviceProvisionedController mDeviceProvisionedController; + + @Inject + UsbAccessoryUriActivity(DeviceProvisionedController deviceProvisionedController) { + mDeviceProvisionedController = deviceProvisionedController; + } + @Override public void onCreate(Bundle icicle) { - getWindow().addSystemFlags( + getWindow().addSystemFlags( WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); - super.onCreate(icicle); + super.onCreate(icicle); + + // Don't show this dialog during Setup Wizard + if (!mDeviceProvisionedController.isDeviceProvisioned()) { + Log.e(TAG, "device not provisioned"); + finish(); + return; + } - Intent intent = getIntent(); + Intent intent = getIntent(); mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); String uriString = intent.getStringExtra("uri"); mUri = (uriString == null ? null : Uri.parse(uriString)); diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java index 81ae6e851fb9..c72853ef37be 100644 --- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java @@ -115,6 +115,17 @@ public abstract class SysUIConcurrencyModule { } /** + * Provide a Long running Executor. + */ + @Provides + @SysUISingleton + @LongRunning + public static DelayableExecutor provideLongRunningDelayableExecutor( + @LongRunning Looper looper) { + return new ExecutorImpl(looper); + } + + /** * Provide a Background-Thread Executor. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java index 76a01b918952..54b30300ba49 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java @@ -41,7 +41,7 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.LongRunning; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -71,17 +71,16 @@ public class ImageWallpaper extends WallpaperService { private HandlerThread mWorker; // used for most tasks (call canvas.drawBitmap, load/unload the bitmap) - @Background - private final DelayableExecutor mBackgroundExecutor; + @LongRunning + private final DelayableExecutor mLongExecutor; // wait at least this duration before unloading the bitmap private static final int DELAY_UNLOAD_BITMAP = 2000; @Inject - public ImageWallpaper(@Background DelayableExecutor backgroundExecutor, - UserTracker userTracker) { + public ImageWallpaper(@LongRunning DelayableExecutor longExecutor, UserTracker userTracker) { super(); - mBackgroundExecutor = backgroundExecutor; + mLongExecutor = longExecutor; mUserTracker = userTracker; } @@ -131,7 +130,7 @@ public class ImageWallpaper extends WallpaperService { setFixedSizeAllowed(true); setShowForAllUsers(true); mWallpaperLocalColorExtractor = new WallpaperLocalColorExtractor( - mBackgroundExecutor, + mLongExecutor, new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() { @Override public void onColorsProcessed(List<RectF> regions, @@ -230,7 +229,7 @@ public class ImageWallpaper extends WallpaperService { } private void drawFrame() { - mBackgroundExecutor.execute(this::drawFrameSynchronized); + mLongExecutor.execute(this::drawFrameSynchronized); } private void drawFrameSynchronized() { @@ -285,7 +284,7 @@ public class ImageWallpaper extends WallpaperService { } private void unloadBitmapIfNotUsed() { - mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized); + mLongExecutor.execute(this::unloadBitmapIfNotUsedSynchronized); } private void unloadBitmapIfNotUsedSynchronized() { @@ -381,7 +380,7 @@ public class ImageWallpaper extends WallpaperService { * - the mini bitmap from color extractor is recomputed * - the DELAY_UNLOAD_BITMAP has passed */ - mBackgroundExecutor.executeDelayed( + mLongExecutor.executeDelayed( this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP); } // even if the bitmap cannot be loaded, call reportEngineShown diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java index 988fd710d2dc..1e8446f8df1d 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java @@ -29,7 +29,7 @@ import android.util.MathUtils; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.LongRunning; import com.android.systemui.util.Assert; import java.io.FileDescriptor; @@ -66,8 +66,8 @@ public class WallpaperLocalColorExtractor { private final List<RectF> mPendingRegions = new ArrayList<>(); private final Set<RectF> mProcessedRegions = new ArraySet<>(); - @Background - private final Executor mBackgroundExecutor; + @LongRunning + private final Executor mLongExecutor; private final WallpaperLocalColorExtractorCallback mWallpaperLocalColorExtractorCallback; @@ -101,13 +101,13 @@ public class WallpaperLocalColorExtractor { /** * Creates a new color extractor. - * @param backgroundExecutor the executor on which the color extraction will be performed + * @param longExecutor the executor on which the color extraction will be performed * @param wallpaperLocalColorExtractorCallback an interface to handle the callbacks from * the color extractor. */ - public WallpaperLocalColorExtractor(@Background Executor backgroundExecutor, + public WallpaperLocalColorExtractor(@LongRunning Executor longExecutor, WallpaperLocalColorExtractorCallback wallpaperLocalColorExtractorCallback) { - mBackgroundExecutor = backgroundExecutor; + mLongExecutor = longExecutor; mWallpaperLocalColorExtractorCallback = wallpaperLocalColorExtractorCallback; } @@ -117,7 +117,7 @@ public class WallpaperLocalColorExtractor { * not recomputed. */ public void setDisplayDimensions(int displayWidth, int displayHeight) { - mBackgroundExecutor.execute(() -> + mLongExecutor.execute(() -> setDisplayDimensionsSynchronized(displayWidth, displayHeight)); } @@ -144,7 +144,7 @@ public class WallpaperLocalColorExtractor { * @param bitmap the new wallpaper */ public void onBitmapChanged(@NonNull Bitmap bitmap) { - mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap)); + mLongExecutor.execute(() -> onBitmapChangedSynchronized(bitmap)); } private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) { @@ -167,7 +167,7 @@ public class WallpaperLocalColorExtractor { * @param pages the total number of pages of the launcher */ public void onPageChanged(int pages) { - mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages)); + mLongExecutor.execute(() -> onPageChangedSynchronized(pages)); } private void onPageChangedSynchronized(int pages) { @@ -194,7 +194,7 @@ public class WallpaperLocalColorExtractor { */ public void addLocalColorsAreas(@NonNull List<RectF> regions) { if (regions.size() > 0) { - mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions)); + mLongExecutor.execute(() -> addLocalColorsAreasSynchronized(regions)); } else { Log.w(TAG, "Attempt to add colors with an empty list"); } @@ -218,7 +218,7 @@ public class WallpaperLocalColorExtractor { * @param regions The areas of interest in our wallpaper (in screen pixel coordinates) */ public void removeLocalColorAreas(@NonNull List<RectF> regions) { - mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions)); + mLongExecutor.execute(() -> removeLocalColorAreasSynchronized(regions)); } private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) { @@ -236,7 +236,7 @@ public class WallpaperLocalColorExtractor { * Clean up the memory (in particular, the mini bitmap) used by this class. */ public void cleanUp() { - mBackgroundExecutor.execute(this::cleanUpSynchronized); + mLongExecutor.execute(this::cleanUpSynchronized); } private void cleanUpSynchronized() { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 9600fd88a2a3..08f7eaee3011 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -25,7 +25,6 @@ import static android.service.notification.NotificationListenerService.REASON_GR import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE; import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; -import static com.android.systemui.flags.Flags.WM_BUBBLE_BAR; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; @@ -364,7 +363,6 @@ public class BubblesManager { }); } }; - mBubbles.setBubbleBarEnabled(featureFlags.isEnabled(WM_BUBBLE_BAR)); mBubbles.setSysuiProxy(mSysuiProxy); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 1bbc19931c21..531006da8210 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -37,6 +37,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -160,6 +161,29 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { } @Test + public void testOnApplyWindowInsets_disappearAnimation_paddingNotSet() { + int paddingBottom = getContext().getResources() + .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin); + int imeInsetAmount = paddingBottom + 1; + int systemBarInsetAmount = 0; + initMode(MODE_DEFAULT); + + Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); + Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); + + WindowInsets insets = new WindowInsets.Builder() + .setInsets(ime(), imeInset) + .setInsetsIgnoringVisibility(systemBars(), systemBarInset) + .build(); + + ensureViewFlipperIsMocked(); + mKeyguardSecurityContainer.startDisappearAnimation( + KeyguardSecurityModel.SecurityMode.Password); + mKeyguardSecurityContainer.onApplyWindowInsets(insets); + assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isNotEqualTo(imeInsetAmount); + } + + @Test public void testDefaultViewMode() { initMode(MODE_ONE_HANDED); initMode(MODE_DEFAULT); @@ -376,6 +400,17 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1); } + @Test + public void testDisappearAnimationPassword() { + ensureViewFlipperIsMocked(); + KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class); + when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView); + + mKeyguardSecurityContainer + .startDisappearAnimation(KeyguardSecurityModel.SecurityMode.Password); + verify(keyguardPasswordView).setDisappearAnimationListener(any()); + } + private BackEvent createBackEvent(float touchX, float progress) { return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT); } @@ -446,4 +481,12 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { mUserSwitcherController, () -> { }, mFalsingA11yDelegate); } + + private void ensureViewFlipperIsMocked() { + mSecurityViewFlipper = mock(KeyguardSecurityViewFlipper.class); + KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class); + when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView); + mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper; + } + } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index bd77c327e765..86ba30cee7a3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -2210,6 +2210,32 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testPostureChangeToUnsupported_stopsFaceListeningState() { + // GIVEN device is listening for face + mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED; + deviceInPostureStateClosed(); + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mTestableLooper.processAllMessages(); + keyguardIsVisible(); + + verifyFaceAuthenticateCall(); + + final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal); + mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel; + KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); + mKeyguardUpdateMonitor.registerCallback(callback); + + // WHEN device is opened + deviceInPostureStateOpened(); + mTestableLooper.processAllMessages(); + + // THEN face listening is stopped. + verify(faceCancel).cancel(); + verify(callback).onBiometricRunningStateChanged( + eq(false), eq(BiometricSourceType.FACE)); + } + + @Test public void testShouldListenForFace_withLockedDown_returnsFalse() throws RemoteException { keyguardNotGoingAway(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java index 47c91911e52a..52a70ee9cce2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java @@ -201,6 +201,13 @@ public class WindowMagnificationSettingsTest extends SysuiTestCase { assertThat(magnifierMediumButton.isSelected()).isTrue(); } + @Test + public void showSettingPanel_focusOnThePanel() { + mWindowMagnificationSettings.showSettingPanel(); + + assertThat(mSettingView.isFocused()).isTrue(); + } + private <T extends View> T getInternalView(@IdRes int idRes) { T view = mSettingView.findViewById(idRes); assertNotNull(view); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index b765ab3c5eac..a245c01d74de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -25,7 +25,9 @@ import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.keyguard.logging.KeyguardLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FeatureFlags import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -109,6 +111,7 @@ class AuthRippleControllerTest : SysuiTestCase() { udfpsControllerProvider, statusBarStateController, featureFlags, + KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)), rippleView ) controller.init() diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java index faa5db4327a6..ab6d5b771d5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java @@ -94,7 +94,9 @@ public class DistanceClassifierTest extends ClassifierTest { mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3)); mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300)); mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301)); - mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); + mClassifier.onTouchEvent(appendMoveEvent(1, 19, 501)); + mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); //event will be dropped + assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java index 2edc3d361316..8eadadff1ca5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java @@ -75,16 +75,17 @@ public class FalsingDataProviderTest extends ClassifierTest { } @Test - public void test_trackMotionEvents() { + public void test_trackMotionEvents_dropUpEvent() { mDataProvider.onMotionEvent(appendDownEvent(2, 9)); mDataProvider.onMotionEvent(appendMoveEvent(4, 7)); - mDataProvider.onMotionEvent(appendUpEvent(6, 5)); + mDataProvider.onMotionEvent(appendMoveEvent(6, 5)); + mDataProvider.onMotionEvent(appendUpEvent(0, 0)); // event will be dropped List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents(); assertThat(motionEventList.size()).isEqualTo(3); assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN); assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE); - assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP); + assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE); assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L); assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L); assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L); @@ -97,6 +98,28 @@ public class FalsingDataProviderTest extends ClassifierTest { } @Test + public void test_trackMotionEvents_keepUpEvent() { + mDataProvider.onMotionEvent(appendDownEvent(2, 9)); + mDataProvider.onMotionEvent(appendMoveEvent(4, 7)); + mDataProvider.onMotionEvent(appendUpEvent(0, 0, 100)); + List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents(); + + assertThat(motionEventList.size()).isEqualTo(3); + assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN); + assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE); + assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP); + assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L); + assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L); + assertThat(motionEventList.get(2).getEventTime()).isEqualTo(100); + assertThat(motionEventList.get(0).getX()).isEqualTo(2f); + assertThat(motionEventList.get(1).getX()).isEqualTo(4f); + assertThat(motionEventList.get(2).getX()).isEqualTo(0f); + assertThat(motionEventList.get(0).getY()).isEqualTo(9f); + assertThat(motionEventList.get(1).getY()).isEqualTo(7f); + assertThat(motionEventList.get(2).getY()).isEqualTo(0f); + } + + @Test public void test_trackRecentMotionEvents() { mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1)); mDataProvider.onMotionEvent(appendMoveEvent(4, 7, 800)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java index c343c20398e9..ae2b8bbb4ce6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java @@ -68,6 +68,15 @@ public class ZigZagClassifierTest extends ClassifierTest { } @Test + public void testPass_dropClosingUpEvent() { + appendMoveEvent(0, 0); + appendMoveEvent(0, 100); + appendMoveEvent(0, 200); + appendUpEvent(0, 180); // this event would push us over the maxDevianceY + assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse(); + } + + @Test public void testPass_fewTouchesHorizontal() { assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse(); appendMoveEvent(0, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java index 2099281d694a..c2fb904f64ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -446,7 +446,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true); when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString())) .thenReturn(true); - when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString())) + when(mClipboardUtils.getAction(any(TextLinks.class), anyString())) .thenReturn(Optional.of(Mockito.mock(RemoteAction.class))); when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() { @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java index aea6be3d468b..3d8f04e08825 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; @@ -77,6 +78,74 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { @Test public void test_getAction_noLinks_returnsEmptyOptional() { + Optional<RemoteAction> action = + mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc"); + + assertTrue(action.isEmpty()); + } + + @Test + public void test_getAction_returnsFirstLink() { + TextLinks links = getFakeTextLinksBuilder().build(); + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( + classificationA, classificationB); + + RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null); + + assertEquals(actionA, result); + } + + @Test + public void test_getAction_skipsMatchingComponent() { + TextLinks links = getFakeTextLinksBuilder().build(); + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( + classificationA, classificationB); + + RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null); + + assertEquals(actionB, result); + } + + @Test + public void test_getAction_skipsShortEntity() { + TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); + final Map<String, Float> scores = new ArrayMap<>(); + scores.put(TextClassifier.TYPE_EMAIL, 1f); + textLinks.addLink(20, 22, scores); + textLinks.addLink(0, 22, scores); + + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn( + classificationA); + when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn( + classificationB); + + RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null); + + assertEquals(actionB, result); + } + + // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once + // CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed + @Test + public void test_getAction_noLinks_returnsEmptyOptional_legacy() { ClipData.Item item = new ClipData.Item("no text links"); item.setTextLinks(Mockito.mock(TextLinks.class)); @@ -86,8 +155,8 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { } @Test - public void test_getAction_returnsFirstLink() { - when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks()); + public void test_getAction_returnsFirstLink_legacy() { + when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build()); when(mClipDataItem.getText()).thenReturn(""); RemoteAction actionA = constructRemoteAction("abc"); RemoteAction actionB = constructRemoteAction("def"); @@ -98,14 +167,14 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( classificationA, classificationB); - RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null); + RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null); assertEquals(actionA, result); } @Test - public void test_getAction_skipsMatchingComponent() { - when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks()); + public void test_getAction_skipsMatchingComponent_legacy() { + when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build()); when(mClipDataItem.getText()).thenReturn(""); RemoteAction actionA = constructRemoteAction("abc"); RemoteAction actionB = constructRemoteAction("def"); @@ -122,6 +191,33 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { } @Test + public void test_getAction_skipsShortEntity_legacy() { + TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); + final Map<String, Float> scores = new ArrayMap<>(); + scores.put(TextClassifier.TYPE_EMAIL, 1f); + textLinks.addLink(20, 22, scores); + textLinks.addLink(0, 22, scores); + + when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build()); + when(mClipDataItem.getText()).thenReturn(textLinks.build().getText()); + + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn( + classificationA); + when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn( + classificationB); + + RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null); + + assertEquals(actionB, result); + } + + @Test public void test_extra_withPackage_returnsTrue() { PersistableBundle b = new PersistableBundle(); b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true); @@ -184,12 +280,12 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { return action; } - private static TextLinks getFakeTextLinks() { - TextLinks.Builder textLinks = new TextLinks.Builder("test"); + private static TextLinks.Builder getFakeTextLinksBuilder() { + TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); final Map<String, Float> scores = new ArrayMap<>(); scores.put(TextClassifier.TYPE_EMAIL, 1f); - textLinks.addLink(0, 0, scores); - textLinks.addLink(0, 0, scores); - return textLinks.build(); + textLinks.addLink(0, 22, scores); + textLinks.addLink(0, 22, scores); + return textLinks; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index 3a168d4e234b..d6dbd730368e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -450,6 +450,15 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { swipeToPosition(0f, Direction.DOWN, 0); } + @Test + public void testTouchSessionOnRemovedCalledTwice() { + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor<DreamTouchHandler.TouchSession.Callback> onRemovedCallbackCaptor = + ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.Callback.class); + verify(mTouchSession).registerCallback(onRemovedCallbackCaptor.capture()); + onRemovedCallbackCaptor.getValue().onRemoved(); + onRemovedCallbackCaptor.getValue().onRemoved(); + } private void swipeToPosition(float percent, Direction direction, float velocityY) { Mockito.clearInvocations(mTouchSession); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt new file mode 100644 index 000000000000..ec94cdec78f0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyboard.backlight.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository +import com.android.systemui.keyboard.shared.model.BacklightModel +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class KeyboardBacklightInteractorTest : SysuiTestCase() { + + private val keyboardRepository = FakeKeyboardRepository() + private lateinit var underTest: KeyboardBacklightInteractor + + @Before + fun setUp() { + underTest = KeyboardBacklightInteractor(keyboardRepository) + } + + @Test + fun emitsNull_whenKeyboardJustConnected() = runTest { + val latest by collectLastValue(underTest.backlight) + keyboardRepository.setKeyboardConnected(true) + + assertThat(latest).isNull() + } + + @Test + fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest { + keyboardRepository.setKeyboardConnected(true) + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5)) + } + + @Test + fun emitsNull_afterKeyboardDisconnecting() = runTest { + val latest by collectLastValue(underTest.backlight) + keyboardRepository.setKeyboardConnected(true) + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + keyboardRepository.setKeyboardConnected(false) + + assertThat(latest).isNull() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt new file mode 100644 index 000000000000..ec05d10b793c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt @@ -0,0 +1,102 @@ +/* + * 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.keyboard.backlight.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor +import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository +import com.android.systemui.keyboard.shared.model.BacklightModel +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class BacklightDialogViewModelTest : SysuiTestCase() { + + private val keyboardRepository = FakeKeyboardRepository() + private lateinit var underTest: BacklightDialogViewModel + @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper + private val timeoutMillis = 3000L + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any())) + .thenReturn(timeoutMillis.toInt()) + underTest = + BacklightDialogViewModel( + KeyboardBacklightInteractor(keyboardRepository), + accessibilityManagerWrapper + ) + keyboardRepository.setKeyboardConnected(true) + } + + @Test + fun emitsViewModel_whenBacklightChanged() = runTest { + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5)) + } + + @Test + fun emitsNull_afterTimeout() = runTest { + val latest by collectLastValue(underTest.dialogContent) + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5)) + advanceTimeBy(timeoutMillis + 1) + assertThat(latest).isNull() + } + + @Test + fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest { + val latest by collectLastValue(underTest.dialogContent) + keyboardRepository.setKeyboardConnected(true) + + keyboardRepository.setBacklight(BacklightModel(1, 5)) + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5)) + + advanceTimeBy(timeoutMillis * 2 / 3) + // timeout yet to pass, no new emission + keyboardRepository.setBacklight(BacklightModel(2, 5)) + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5)) + + advanceTimeBy(timeoutMillis * 2 / 3) + // timeout refreshed because of last `setBacklight`, still content present + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5)) + + advanceTimeBy(timeoutMillis * 2 / 3) + // finally timeout reached and null emitted + assertThat(latest).isNull() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt index a4e5bcaecde4..984f4be0ae97 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt @@ -45,6 +45,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRendererFactory import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager @@ -91,6 +92,7 @@ class CustomizationProviderTest : SysuiTestCase() { @Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager + @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger private lateinit var underTest: CustomizationProvider private lateinit var testScope: TestScope @@ -184,6 +186,7 @@ class CustomizationProviderTest : SysuiTestCase() { featureFlags = featureFlags, repository = { quickAffordanceRepository }, launchAnimator = launchAnimator, + logger = logger, devicePolicyManager = devicePolicyManager, backgroundDispatcher = testDispatcher, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt index 84ec125bfa55..46c623a7d3c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt @@ -42,6 +42,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.UserFileManager @@ -225,6 +226,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { @Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager + @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger private lateinit var underTest: KeyguardQuickAffordanceInteractor private lateinit var testScope: TestScope @@ -331,6 +333,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { featureFlags = featureFlags, repository = { quickAffordanceRepository }, launchAnimator = launchAnimator, + logger = logger, devicePolicyManager = devicePolicyManager, backgroundDispatcher = testDispatcher, ) @@ -360,10 +363,11 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } - underTest.onQuickAffordanceTriggered( - configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, - expandable = expandable, - ) + underTest.onQuickAffordanceTriggered( + configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, + expandable = expandable, + slotId = "", + ) if (startActivity) { if (needsToUnlockFirst) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 62c9e5ffbb51..cd579dbc132e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -45,6 +45,7 @@ import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAff import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker @@ -80,6 +81,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager + @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger private lateinit var underTest: KeyguardQuickAffordanceInteractor @@ -186,6 +188,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { featureFlags = featureFlags, repository = { quickAffordanceRepository }, launchAnimator = launchAnimator, + logger = logger, devicePolicyManager = devicePolicyManager, backgroundDispatcher = testDispatcher, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index c727b3a6cd10..bfc09d7c0379 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -45,6 +45,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceIn import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition +import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker @@ -89,6 +90,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { @Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager + @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger private lateinit var underTest: KeyguardBottomAreaViewModel @@ -208,6 +210,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { featureFlags = featureFlags, repository = { quickAffordanceRepository }, launchAnimator = launchAnimator, + logger = logger, devicePolicyManager = devicePolicyManager, backgroundDispatcher = testDispatcher, ), @@ -230,6 +233,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -260,6 +264,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -272,6 +277,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { testConfig = TestConfig( isVisible = false, + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ), configKey = configKey, ) @@ -299,6 +305,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = icon, canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ), ) @@ -313,6 +320,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { canShowWhileLocked = false, intent = Intent("action"), isSelected = true, + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ), configKey = configKey, ) @@ -341,6 +349,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = icon, canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ), ) val configKey = @@ -354,6 +363,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = icon, canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), ), ) @@ -368,6 +378,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { canShowWhileLocked = false, intent = Intent("action"), isDimmed = true, + slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), ), configKey = configKey, ) @@ -387,6 +398,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { canShowWhileLocked = false, intent = null, // This will cause it to tell the system that the click was handled. + slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -409,6 +421,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { val config = TestConfig( isVisible = false, + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -434,6 +447,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) setUpQuickAffordanceModel( @@ -513,6 +527,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { isClickable = true, icon = mock(), canShowWhileLocked = true, + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) ) assertThat(value()).isTrue() @@ -524,6 +539,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { isClickable = true, icon = mock(), canShowWhileLocked = false, + slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), ) ) assertThat(value()).isTrue() @@ -532,6 +548,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { testConfig = TestConfig( isVisible = false, + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) ) assertThat(value()).isTrue() @@ -540,6 +557,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { testConfig = TestConfig( isVisible = false, + slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(), ) ) assertThat(value()).isFalse() @@ -594,6 +612,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -626,6 +645,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -656,6 +676,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -684,6 +705,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { icon = mock(), canShowWhileLocked = false, intent = Intent("action"), + slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(), ) val configKey = setUpQuickAffordanceModel( @@ -748,12 +770,14 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { assertThat(viewModel.isActivated).isEqualTo(testConfig.isActivated) assertThat(viewModel.isSelected).isEqualTo(testConfig.isSelected) assertThat(viewModel.isDimmed).isEqualTo(testConfig.isDimmed) + assertThat(viewModel.slotId).isEqualTo(testConfig.slotId) if (testConfig.isVisible) { assertThat(viewModel.icon).isEqualTo(testConfig.icon) viewModel.onClicked.invoke( KeyguardQuickAffordanceViewModel.OnClickedParameters( configKey = configKey, expandable = expandable, + slotId = viewModel.slotId, ) ) if (testConfig.intent != null) { @@ -775,6 +799,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { val intent: Intent? = null, val isSelected: Boolean = false, val isDimmed: Boolean = false, + val slotId: String = "" ) { init { check(!isVisible || icon != null) { "Must supply non-null icon if visible!" } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt new file mode 100644 index 000000000000..2a91799741b7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -0,0 +1,109 @@ +/* + * 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.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.util.mockito.whenever +import com.google.common.collect.Range +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.UnconfinedTestDispatcher +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.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { + private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel + private lateinit var repository: FakeKeyguardTransitionRepository + @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + repository = FakeKeyguardTransitionRepository() + val interactor = KeyguardTransitionInteractor(repository) + underTest = PrimaryBouncerToGoneTransitionViewModel(interactor, statusBarStateController) + } + + @Test + fun scrimBehindAlpha_leaveShadeOpen() = + runTest(UnconfinedTestDispatcher()) { + val values = mutableListOf<Float>() + + val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this) + + whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true) + + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + + assertThat(values.size).isEqualTo(4) + values.forEach { assertThat(it).isEqualTo(1f) } + + job.cancel() + } + + @Test + fun scrimBehindAlpha_doNotLeaveShadeOpen() = + runTest(UnconfinedTestDispatcher()) { + val values = mutableListOf<Float>() + + val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this) + + whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) + + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + + assertThat(values.size).isEqualTo(4) + values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } + assertThat(values[3]).isEqualTo(0f) + + job.cancel() + } + + private fun step( + value: Float, + state: TransitionState = TransitionState.RUNNING + ): TransitionStep { + return TransitionStep( + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.GONE, + value = value, + transitionState = state, + ownerName = "PrimaryBouncerToGoneTransitionViewModelTest" + ) + } +} 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 55a33b6636e0..fd353afff7c0 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 @@ -27,6 +27,7 @@ import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color +import android.graphics.Matrix import android.graphics.drawable.Animatable2 import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.Drawable @@ -78,6 +79,8 @@ import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.media.controls.util.MediaUiEventLogger import com.android.systemui.media.dialog.MediaOutputDialogFactory +import com.android.systemui.monet.ColorScheme +import com.android.systemui.monet.Style import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.NotificationLockscreenUserManager @@ -214,6 +217,7 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var recSubtitleMock2: TextView @Mock private lateinit var recSubtitleMock3: 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 @@ -700,6 +704,46 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun addTwoPlayerGradients_differentStates() { + // Setup redArtwork and its color scheme. + val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val redCanvas = Canvas(redBmp) + redCanvas.drawColor(Color.RED) + val redArt = Icon.createWithBitmap(redBmp) + val redWallpaperColor = player.getWallpaperColor(redArt) + val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT) + + // Setup greenArt and its color scheme. + val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val greenCanvas = Canvas(greenBmp) + greenCanvas.drawColor(Color.GREEN) + val greenArt = Icon.createWithBitmap(greenBmp) + val greenWallpaperColor = player.getWallpaperColor(greenArt) + val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT) + + // Add gradient to both icons. + val redArtwork = player.addGradientToPlayerAlbum(redArt, redColorScheme, 10, 10) + val greenArtwork = player.addGradientToPlayerAlbum(greenArt, greenColorScheme, 10, 10) + + // They should have different constant states as they have different gradient color. + assertThat(redArtwork.getDrawable(1).constantState) + .isNotEqualTo(greenArtwork.getDrawable(1).constantState) + } + + @Test + fun getWallpaperColor_recycledBitmap_notCrashing() { + // Setup redArt icon. + val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val redArt = Icon.createWithBitmap(redBmp) + + // Recycle bitmap of redArt icon. + redArt.bitmap.recycle() + + // get wallpaperColor without illegal exception. + player.getWallpaperColor(redArt) + } + + @Test fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() { useRealConstraintSets() @@ -2092,6 +2136,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3)) whenever(recommendationViewHolder.mediaSubtitles) .thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3)) + whenever(coverItem.imageMatrix).thenReturn(matrix) val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) val canvas = Canvas(bmp) @@ -2127,6 +2172,7 @@ public class MediaControlPanelTest : SysuiTestCase() { verify(recCardTitle).setTextColor(any<Int>()) verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java)) verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java)) + verify(coverItem, times(3)).imageMatrix = any() } @Test @@ -2189,6 +2235,34 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun addTwoRecommendationGradients_differentStates() { + // Setup redArtwork and its color scheme. + val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val redCanvas = Canvas(redBmp) + redCanvas.drawColor(Color.RED) + val redArt = Icon.createWithBitmap(redBmp) + val redWallpaperColor = player.getWallpaperColor(redArt) + val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT) + + // Setup greenArt and its color scheme. + val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val greenCanvas = Canvas(greenBmp) + greenCanvas.drawColor(Color.GREEN) + val greenArt = Icon.createWithBitmap(greenBmp) + val greenWallpaperColor = player.getWallpaperColor(greenArt) + val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT) + + // Add gradient to both icons. + val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10) + val greenArtwork = + player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10) + + // They should have different constant states as they have different gradient color. + assertThat(redArtwork.getDrawable(1).constantState) + .isNotEqualTo(greenArtwork.getDrawable(1).constantState) + } + + @Test fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() { fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true) val semanticActions = diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java index 41ac3213d402..d364f47d78b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java @@ -18,13 +18,21 @@ package com.android.systemui.monet; import static com.android.systemui.monet.utils.ArgbSubject.assertThat; +import static org.junit.Assert.assertTrue; + import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.monet.contrast.Contrast; import com.android.systemui.monet.dynamiccolor.DynamicColor; +import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors; import com.android.systemui.monet.dynamiccolor.ToneDeltaConstraint; import com.android.systemui.monet.dynamiccolor.TonePolarity; import com.android.systemui.monet.hct.Hct; +import com.android.systemui.monet.scheme.DynamicScheme; +import com.android.systemui.monet.scheme.SchemeContent; +import com.android.systemui.monet.scheme.SchemeFidelity; +import com.android.systemui.monet.scheme.SchemeMonochrome; import com.android.systemui.monet.scheme.SchemeTonalSpot; import org.junit.Test; @@ -90,4 +98,92 @@ public final class DynamicColorTest extends SysuiTestCase { final SchemeTonalSpot darkScheme = new SchemeTonalSpot(Hct.fromInt(0xff4285f4), true, 0.0); assertThat(dynamicColor.getArgb(darkScheme)).isSameColorAs(0x33ffffff); } + + @Test + public void respectsContrast() { + final Hct[] seedColors = + new Hct[]{ + Hct.fromInt(0xFFFF0000), + Hct.fromInt(0xFFFFFF00), + Hct.fromInt(0xFF00FF00), + Hct.fromInt(0xFF0000FF) + }; + + final double[] contrastLevels = {-1.0, -0.5, 0.0, 0.5, 1.0}; + + for (Hct seedColor : seedColors) { + for (double contrastLevel : contrastLevels) { + for (boolean isDark : new boolean[]{false, true}) { + final DynamicScheme[] schemes = + new DynamicScheme[]{ + new SchemeContent(seedColor, isDark, contrastLevel), + new SchemeMonochrome(seedColor, isDark, contrastLevel), + new SchemeTonalSpot(seedColor, isDark, contrastLevel), + new SchemeFidelity(seedColor, isDark, contrastLevel) + }; + for (final DynamicScheme scheme : schemes) { + assertTrue( + pairSatisfiesContrast( + scheme, MaterialDynamicColors.onPrimary, + MaterialDynamicColors.primary)); + assertTrue( + pairSatisfiesContrast( + scheme, + MaterialDynamicColors.onPrimaryContainer, + MaterialDynamicColors.primaryContainer)); + assertTrue( + pairSatisfiesContrast( + scheme, MaterialDynamicColors.onSecondary, + MaterialDynamicColors.secondary)); + assertTrue( + pairSatisfiesContrast( + scheme, + MaterialDynamicColors.onSecondaryContainer, + MaterialDynamicColors.secondaryContainer)); + assertTrue( + pairSatisfiesContrast( + scheme, MaterialDynamicColors.onTertiary, + MaterialDynamicColors.tertiary)); + assertTrue( + pairSatisfiesContrast( + scheme, + MaterialDynamicColors.onTertiaryContainer, + MaterialDynamicColors.tertiaryContainer)); + assertTrue( + pairSatisfiesContrast( + scheme, MaterialDynamicColors.onError, + MaterialDynamicColors.error)); + assertTrue( + pairSatisfiesContrast( + scheme, + MaterialDynamicColors.onErrorContainer, + MaterialDynamicColors.errorContainer)); + assertTrue( + pairSatisfiesContrast( + scheme, MaterialDynamicColors.onBackground, + MaterialDynamicColors.background)); + assertTrue( + pairSatisfiesContrast( + scheme, + MaterialDynamicColors.onSurfaceVariant, + MaterialDynamicColors.surfaceVariant)); + assertTrue( + pairSatisfiesContrast( + scheme, + MaterialDynamicColors.onSurfaceInverse, + MaterialDynamicColors.surfaceInverse)); + } + } + } + } + } + + private boolean pairSatisfiesContrast(DynamicScheme scheme, DynamicColor fg, DynamicColor bg) { + double fgTone = fg.getHct(scheme).getTone(); + double bgTone = bg.getHct(scheme).getTone(); + // TODO(b/270915664) - Fix inconsistencies. + // TODO(b/270915664) - Minimum requirement should be 4.5 when not reducing contrast. + double minimumRequirement = 3.0; + return Contrast.ratioOfTones(fgTone, bgTone) >= minimumRequirement; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index 376b7cc70150..4efc30f0aee2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -20,12 +20,17 @@ import android.app.admin.DevicePolicyManager import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK +import android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.PackageManager +import android.os.UserHandle import android.os.UserManager import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.systemui.SysuiTestCase import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity +import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -57,8 +62,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() { @Mock lateinit var keyguardManager: KeyguardManager @Mock lateinit var userManager: UserManager @Mock lateinit var eventLogger: NoteTaskEventLogger - @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var devicePolicyManager: DevicePolicyManager + private val userTracker: UserTracker = FakeUserTracker() private val noteTaskInfo = NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID) @@ -81,16 +86,14 @@ internal class NoteTaskControllerTest : SysuiTestCase() { private fun createNoteTaskController( isEnabled: Boolean = true, bubbles: Bubbles? = this.bubbles, - keyguardManager: KeyguardManager? = this.keyguardManager, - userManager: UserManager? = this.userManager, ): NoteTaskController = NoteTaskController( context = context, resolver = resolver, eventLogger = eventLogger, optionalBubbles = Optional.ofNullable(bubbles), - optionalUserManager = Optional.ofNullable(userManager), - optionalKeyguardManager = Optional.ofNullable(keyguardManager), + userManager = userManager, + keyguardManager = keyguardManager, isEnabled = isEnabled, devicePolicyManager = devicePolicyManager, userTracker = userTracker, @@ -225,13 +228,19 @@ internal class NoteTaskControllerTest : SysuiTestCase() { ) val intentCaptor = argumentCaptor<Intent>() - verify(context).startActivity(capture(intentCaptor)) + val userCaptor = argumentCaptor<UserHandle>() + verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor)) intentCaptor.value.let { intent -> assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE) assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME) - assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags and FLAG_ACTIVITY_MULTIPLE_TASK) + .isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK) + assertThat(intent.flags and FLAG_ACTIVITY_NEW_DOCUMENT) + .isEqualTo(FLAG_ACTIVITY_NEW_DOCUMENT) assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue() } + assertThat(userCaptor.value).isEqualTo(userTracker.userHandle) verify(eventLogger).logNoteTaskOpened(expectedInfo) verifyZeroInteractions(bubbles) } @@ -259,7 +268,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { intentCaptor.value.let { intent -> assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE) assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME) - assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK) assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue() } verifyZeroInteractions(eventLogger) @@ -283,13 +292,22 @@ internal class NoteTaskControllerTest : SysuiTestCase() { ) val intentCaptor = argumentCaptor<Intent>() - verify(context).startActivity(capture(intentCaptor)) + val userCaptor = argumentCaptor<UserHandle>() + verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor)) + + (intentCaptor.value.flags and FLAG_ACTIVITY_NEW_TASK) == FLAG_ACTIVITY_NEW_TASK + intentCaptor.value.let { intent -> assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE) assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME) - assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags and FLAG_ACTIVITY_MULTIPLE_TASK) + .isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK) + assertThat(intent.flags and FLAG_ACTIVITY_NEW_DOCUMENT) + .isEqualTo(FLAG_ACTIVITY_NEW_DOCUMENT) assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue() } + assertThat(userCaptor.value).isEqualTo(userTracker.userHandle) verify(eventLogger).logNoteTaskOpened(expectedInfo) verifyZeroInteractions(bubbles) } @@ -306,28 +324,6 @@ internal class NoteTaskControllerTest : SysuiTestCase() { } @Test - fun showNoteTask_keyguardManagerIsNull_shouldDoNothing() { - createNoteTaskController(keyguardManager = null) - .showNoteTask( - entryPoint = NoteTaskEntryPoint.TAIL_BUTTON, - isInMultiWindowMode = false, - ) - - verifyZeroInteractions(context, bubbles, eventLogger) - } - - @Test - fun showNoteTask_userManagerIsNull_shouldDoNothing() { - createNoteTaskController(userManager = null) - .showNoteTask( - entryPoint = NoteTaskEntryPoint.TAIL_BUTTON, - isInMultiWindowMode = false, - ) - - verifyZeroInteractions(context, bubbles, eventLogger) - } - - @Test fun showNoteTask_intentResolverReturnsNull_shouldDoNothing() { whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(null) @@ -460,7 +456,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { intentCaptor.value.let { intent -> assertThat(intent.action).isEqualTo(NoteTaskController.ACTION_CREATE_NOTE) assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME) - assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK) assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue() } } @@ -487,7 +483,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { intentCaptor.value.let { intent -> assertThat(intent.action).isEqualTo(NoteTaskController.ACTION_CREATE_NOTE) assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME) - assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK) + assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK) assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt index 7f64f8a123e0..0c945dfa4b4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt @@ -22,6 +22,8 @@ import android.content.pm.PackageManager import android.test.suitebuilder.annotation.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat @@ -44,13 +46,14 @@ internal class NoteTaskInfoResolverTest : SysuiTestCase() { @Mock lateinit var packageManager: PackageManager @Mock lateinit var roleManager: RoleManager + private val userTracker: UserTracker = FakeUserTracker() private lateinit var underTest: NoteTaskInfoResolver @Before fun setUp() { MockitoAnnotations.initMocks(this) - underTest = NoteTaskInfoResolver(context, roleManager, packageManager) + underTest = NoteTaskInfoResolver(roleManager, packageManager, userTracker) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS index 7ccb316dbca5..0ec996be72de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS @@ -5,4 +5,6 @@ juliacr@google.com madym@google.com mgalhardo@google.com petrcermak@google.com +stevenckng@google.com +tkachenkoi@google.com vanjan@google.com
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java index 515e1ee172ed..3c08d58cbb67 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java @@ -18,14 +18,14 @@ package com.android.systemui.screenshot.appclips; import static android.app.Activity.RESULT_OK; -import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED; -import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED; +import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_ACCEPTED; +import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_CANCELLED; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -34,36 +34,35 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.ApplicationInfoFlags; import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.ResultReceiver; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.widget.ImageView; -import androidx.lifecycle.MutableLiveData; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.intercepting.SingleActivityFactory; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.screenshot.AppClipsActivity; -import com.android.systemui.screenshot.AppClipsTrampolineActivity; -import com.android.systemui.screenshot.AppClipsViewModel; +import com.android.systemui.screenshot.ImageExporter; import com.android.systemui.settings.UserTracker; +import com.google.common.util.concurrent.Futures; + import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.UUID; +import java.util.concurrent.Executor; import java.util.function.BiConsumer; @RunWith(AndroidTestingRunner.class) @@ -78,18 +77,16 @@ public final class AppClipsActivityTest extends SysuiTestCase { private static final String TEST_CALLING_PACKAGE = "test-calling-package"; @Mock - private AppClipsViewModel.Factory mViewModelFactory; + private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper; + @Mock + private ImageExporter mImageExporter; @Mock private PackageManager mPackageManager; @Mock private UserTracker mUserTracker; @Mock private UiEventLogger mUiEventLogger; - @Mock - private AppClipsViewModel mViewModel; - private MutableLiveData<Bitmap> mScreenshotLiveData; - private MutableLiveData<Uri> mResultLiveData; private AppClipsActivity mActivity; // Using the deprecated ActivityTestRule and SingleActivityFactory to help with injecting mocks. @@ -97,8 +94,11 @@ public final class AppClipsActivityTest extends SysuiTestCase { new SingleActivityFactory<>(AppClipsActivityTestable.class) { @Override protected AppClipsActivityTestable create(Intent unUsed) { - return new AppClipsActivityTestable(mViewModelFactory, mPackageManager, - mUserTracker, mUiEventLogger); + return new AppClipsActivityTestable( + new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, + mImageExporter, getContext().getMainExecutor(), + directExecutor()), mPackageManager, mUserTracker, + mUiEventLogger); } }; @@ -110,29 +110,17 @@ public final class AppClipsActivityTest extends SysuiTestCase { public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); - mScreenshotLiveData = new MutableLiveData<>(); - mResultLiveData = new MutableLiveData<>(); - MutableLiveData<Integer> errorLiveData = new MutableLiveData<>(); - - when(mViewModelFactory.create(any(Class.class))).thenReturn(mViewModel); - when(mViewModel.getScreenshot()).thenReturn(mScreenshotLiveData); - when(mViewModel.getResultLiveData()).thenReturn(mResultLiveData); - when(mViewModel.getErrorLiveData()).thenReturn(errorLiveData); when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID); - ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = TEST_UID; when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE), any(ApplicationInfoFlags.class), eq(TEST_USER_ID))).thenReturn(applicationInfo); - doAnswer(invocation -> { - runOnMainThread(() -> mScreenshotLiveData.setValue(TEST_BITMAP)); - return null; - }).when(mViewModel).performScreenshot(); - doAnswer(invocation -> { - runOnMainThread(() -> mResultLiveData.setValue(TEST_URI)); - return null; - }).when(mViewModel).saveScreenshotThenFinish(any(Drawable.class), any(Rect.class)); + when(mAppClipsCrossProcessHelper.takeScreenshot()).thenReturn(TEST_BITMAP); + ImageExporter.Result result = new ImageExporter.Result(); + result.uri = TEST_URI; + when(mImageExporter.export(any(Executor.class), any(UUID.class), any(Bitmap.class), + any(UserHandle.class))).thenReturn(Futures.immediateFuture(result)); } @After @@ -140,7 +128,6 @@ public final class AppClipsActivityTest extends SysuiTestCase { mActivityRule.finishActivity(); } - @Ignore("b/269403503") @Test public void appClipsLaunched_screenshotDisplayed() { launchActivity(); @@ -148,7 +135,6 @@ public final class AppClipsActivityTest extends SysuiTestCase { assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull(); } - @Ignore("b/269403503") @Test public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() { ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> { @@ -168,7 +154,6 @@ public final class AppClipsActivityTest extends SysuiTestCase { verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_ACCEPTED, TEST_UID, TEST_CALLING_PACKAGE); } - @Ignore("b/269403503") @Test public void screenshotDisplayed_userDeclined() { ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java index e40c49b56ac5..ad06dcc6f327 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java @@ -25,7 +25,8 @@ import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPP import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE; import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS; -import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI; +import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED; +import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI; import static com.google.common.truth.Truth.assertThat; @@ -59,8 +60,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.notetask.NoteTaskController; -import com.android.systemui.screenshot.AppClipsTrampolineActivity; -import com.android.systemui.screenshot.ScreenshotEvent; import com.android.systemui.settings.UserTracker; import com.android.wm.shell.bubbles.Bubbles; @@ -262,8 +261,7 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { mActivityRule.launchActivity(mActivityIntent); waitForIdleSync(); - verify(mUiEventLogger).log(ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID, - TEST_CALLING_PACKAGE); + verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID, TEST_CALLING_PACKAGE); } private void mockToSatisfyAllPrerequisites() throws NameNotFoundException { diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java index d5af7ce1d346..e7c3c0578627 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.screenshot; +package com.android.systemui.screenshot.appclips; import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED; @@ -36,7 +36,7 @@ import android.os.UserHandle; import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; -import com.android.systemui.screenshot.appclips.AppClipsCrossProcessHelper; +import com.android.systemui.screenshot.ImageExporter; import com.google.common.util.concurrent.Futures; @@ -46,7 +46,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.time.ZonedDateTime; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -62,7 +61,7 @@ public final class AppClipsViewModelTest extends SysuiTestCase { @Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper; @Mock private ImageExporter mImageExporter; - private com.android.systemui.screenshot.AppClipsViewModel mViewModel; + private AppClipsViewModel mViewModel; @Before public void setUp() { @@ -99,8 +98,8 @@ public final class AppClipsViewModelTest extends SysuiTestCase { @Test public void saveScreenshot_throwsError_shouldUpdateErrorWithFailed() { - when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), any( - ZonedDateTime.class), any(UserHandle.class))).thenReturn( + when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), + any(UserHandle.class))).thenReturn( Futures.immediateFailedFuture(new ExecutionException(new Throwable()))); mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT); @@ -113,9 +112,9 @@ public final class AppClipsViewModelTest extends SysuiTestCase { @Test public void saveScreenshot_failsSilently_shouldUpdateErrorWithFailed() { - when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), any( - ZonedDateTime.class), any(UserHandle.class))).thenReturn( - Futures.immediateFuture(new ImageExporter.Result())); + when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), + any(UserHandle.class))).thenReturn( + Futures.immediateFuture(new ImageExporter.Result())); mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT); waitForIdleSync(); @@ -129,9 +128,8 @@ public final class AppClipsViewModelTest extends SysuiTestCase { public void saveScreenshot_succeeds_shouldUpdateResultWithUri() { ImageExporter.Result result = new ImageExporter.Result(); result.uri = FAKE_URI; - when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), any( - ZonedDateTime.class), any(UserHandle.class))).thenReturn( - Futures.immediateFuture(result)); + when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), + any(UserHandle.class))).thenReturn(Futures.immediateFuture(result)); mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT); waitForIdleSync(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java index 4478039912c8..64e58d0de2b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java @@ -49,6 +49,7 @@ import android.window.TransitionInfo; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.wm.shell.util.TransitionUtil; import org.junit.Before; import org.junit.Test; @@ -120,7 +121,7 @@ public class RemoteTransitionTest extends SysuiTestCase { change.setTaskInfo(createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_HOME)); change.setEndAbsBounds(endBounds); change.setEndRelOffset(0, 0); - RemoteAnimationTarget wrapped = RemoteAnimationTargetCompat.newTarget( + RemoteAnimationTarget wrapped = TransitionUtil.newTarget( change, 0 /* order */, tinfo, mock(SurfaceControl.Transaction.class), null); assertEquals(ACTIVITY_TYPE_HOME, wrapped.windowConfiguration.getActivityType()); assertEquals(new Rect(0, 0, 100, 140), wrapped.localBounds); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index d99cdd514f37..ab615f99ebad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -211,16 +211,6 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { } @Test - fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() { - whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn( - false) - transitionController.goToLockedShade(null) - verify(statusbarStateController, never()).setState(anyInt()) - verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true) - verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) - } - - @Test fun testTriggeringBouncerNoNotificationsOnLockscreen() { whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false) transitionController.goToLockedShade(null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java index eb5edbc21d89..f5b7ca804fbc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java @@ -180,6 +180,7 @@ public class DozeParametersTest extends SysuiTestCase { when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1"); + verify(mScreenOffAnimationController).onAlwaysOnChanged(false); assertThat(mDozeParameters.getAlwaysOn()).isFalse(); } @@ -196,13 +197,16 @@ public class DozeParametersTest extends SysuiTestCase { mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true); verify(callback, times(2)).onAlwaysOnChange(); + verify(mScreenOffAnimationController, times(2)).onAlwaysOnChanged(false); assertThat(mDozeParameters.getAlwaysOn()).isFalse(); + reset(mScreenOffAnimationController); reset(callback); when(mBatteryController.isAodPowerSave()).thenReturn(false); mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true); verify(callback).onAlwaysOnChange(); + verify(mScreenOffAnimationController).onAlwaysOnChanged(true); assertThat(mDozeParameters.getAlwaysOn()).isTrue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 180d9f8956c3..e1fba816382c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -67,6 +67,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.scrim.ScrimView; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.FakeConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; @@ -127,6 +128,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; @Mock private CoroutineDispatcher mMainDispatcher; + @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController; // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @@ -240,7 +242,8 @@ public class ScrimControllerTest extends SysuiTestCase { when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition()) .thenReturn(emptyFlow()); - when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha()).thenReturn(emptyFlow()); + when(mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha()) + .thenReturn(emptyFlow()); mScrimController = new ScrimController(mLightBarController, mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder, @@ -251,6 +254,7 @@ public class ScrimControllerTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mPrimaryBouncerToGoneTransitionViewModel, mKeyguardTransitionInteractor, + mSysuiStatusBarStateController, mMainDispatcher); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); @@ -884,6 +888,7 @@ public class ScrimControllerTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mPrimaryBouncerToGoneTransitionViewModel, mKeyguardTransitionInteractor, + mSysuiStatusBarStateController, mMainDispatcher); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); @@ -1664,6 +1669,16 @@ public class ScrimControllerTest extends SysuiTestCase { assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED); } + @Test + public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() { + when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true); + mScrimController.mPrimaryBouncerToGoneTransition.accept( + new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f, + TransitionState.FINISHED, "ScrimControllerTest")); + + verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway(); + } + private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) { mScrimController.setRawPanelExpansionFraction(expansion); finishAnimationsImmediately(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS index 7ccb316dbca5..0ec996be72de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS +++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS @@ -5,4 +5,6 @@ juliacr@google.com madym@google.com mgalhardo@google.com petrcermak@google.com +stevenckng@google.com +tkachenkoi@google.com vanjan@google.com
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt index f8bf4b91e11a..4525ad27b749 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt @@ -65,8 +65,6 @@ class StylusManagerTest : SysuiTestCase() { @Mock lateinit var uiEventLogger: UiEventLogger @Mock lateinit var stylusCallback: StylusManager.StylusCallback @Mock lateinit var otherStylusCallback: StylusManager.StylusCallback - @Mock lateinit var stylusBatteryCallback: StylusManager.StylusBatteryCallback - @Mock lateinit var otherStylusBatteryCallback: StylusManager.StylusBatteryCallback private lateinit var mockitoSession: StaticMockitoSession private lateinit var stylusManager: StylusManager @@ -123,7 +121,6 @@ class StylusManagerTest : SysuiTestCase() { stylusManager.startListener() stylusManager.registerCallback(stylusCallback) - stylusManager.registerBatteryCallback(stylusBatteryCallback) clearInvocations(inputManager) } @@ -434,23 +431,6 @@ class StylusManagerTest : SysuiTestCase() { } @Test - fun onMetadataChanged_multipleRegisteredBatteryCallbacks_executesAll() { - stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) - stylusManager.registerBatteryCallback(otherStylusBatteryCallback) - - stylusManager.onMetadataChanged( - bluetoothDevice, - BluetoothDevice.METADATA_MAIN_CHARGING, - "true".toByteArray() - ) - - verify(stylusBatteryCallback, times(1)) - .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true) - verify(otherStylusBatteryCallback, times(1)) - .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true) - } - - @Test fun onMetadataChanged_chargingStateTrue_executesBatteryCallbacks() { stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) @@ -460,7 +440,7 @@ class StylusManagerTest : SysuiTestCase() { "true".toByteArray() ) - verify(stylusBatteryCallback, times(1)) + verify(stylusCallback, times(1)) .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true) } @@ -474,7 +454,7 @@ class StylusManagerTest : SysuiTestCase() { "false".toByteArray() ) - verify(stylusBatteryCallback, times(1)) + verify(stylusCallback, times(1)) .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, false) } @@ -486,7 +466,7 @@ class StylusManagerTest : SysuiTestCase() { "true".toByteArray() ) - verifyNoMoreInteractions(stylusBatteryCallback) + verifyNoMoreInteractions(stylusCallback) } @Test @@ -499,8 +479,7 @@ class StylusManagerTest : SysuiTestCase() { "true".toByteArray() ) - verify(stylusBatteryCallback, never()) - .onStylusBluetoothChargingStateChanged(any(), any(), any()) + verify(stylusCallback, never()).onStylusBluetoothChargingStateChanged(any(), any(), any()) } @Test @@ -614,7 +593,7 @@ class StylusManagerTest : SysuiTestCase() { fun onBatteryStateChanged_executesBatteryCallbacks() { stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) - verify(stylusBatteryCallback, times(1)) + verify(stylusCallback, times(1)) .onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt index 82b80f53d6b0..3db0ecc4e8df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt @@ -96,7 +96,6 @@ class StylusUsiPowerStartableTest : SysuiTestCase() { startable.start() verify(stylusManager, times(1)).registerCallback(startable) - verify(stylusManager, times(1)).registerBatteryCallback(startable) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt index 85cfef727954..fd368eb07b5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt @@ -16,22 +16,24 @@ package com.android.systemui.unfold.updates +import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Looper import android.testing.AndroidTestingRunner -import android.view.IRotationWatcher -import android.view.IWindowManager +import android.view.Display import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener -import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.utils.os.FakeHandler import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations @@ -42,19 +44,23 @@ class RotationChangeProviderTest : SysuiTestCase() { private lateinit var rotationChangeProvider: RotationChangeProvider - @Mock lateinit var windowManagerInterface: IWindowManager + @Mock lateinit var displayManager: DisplayManager @Mock lateinit var listener: RotationListener - @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher> - private val fakeExecutor = FakeExecutor(FakeSystemClock()) + @Mock lateinit var display: Display + @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener> + private val fakeHandler = FakeHandler(Looper.getMainLooper()) + + private lateinit var spyContext: Context @Before fun setup() { MockitoAnnotations.initMocks(this) - rotationChangeProvider = - RotationChangeProvider(windowManagerInterface, context, fakeExecutor) + spyContext = spy(context) + whenever(spyContext.display).thenReturn(display) + rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler) rotationChangeProvider.addCallback(listener) - fakeExecutor.runAllReady() - verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt()) + fakeHandler.dispatchQueuedMessages() + verify(displayManager).registerDisplayListener(displayListener.capture(), any()) } @Test @@ -70,15 +76,16 @@ class RotationChangeProviderTest : SysuiTestCase() { verify(listener).onRotationChanged(42) rotationChangeProvider.removeCallback(listener) - fakeExecutor.runAllReady() + fakeHandler.dispatchQueuedMessages() sendRotationUpdate(43) - verify(windowManagerInterface).removeRotationWatcher(any()) + verify(displayManager).unregisterDisplayListener(any()) verifyNoMoreInteractions(listener) } private fun sendRotationUpdate(newRotation: Int) { - rotationWatcher.value.onRotationChanged(newRotation) - fakeExecutor.runAllReady() + whenever(display.rotation).thenReturn(newRotation) + displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) } + fakeHandler.dispatchQueuedMessages() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java index 31cce4f3168b..468c5a73645b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java @@ -88,7 +88,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Mock private Bitmap mWallpaperBitmap; FakeSystemClock mFakeSystemClock = new FakeSystemClock(); - FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock); + FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); @Before public void setUp() throws Exception { @@ -125,7 +125,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Test public void testBitmapWallpaper_normal() { - // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH. + // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH. // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH. int bitmapSide = DISPLAY_WIDTH; testSurfaceHelper( @@ -137,7 +137,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Test public void testBitmapWallpaper_low_resolution() { - // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT. + // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT. // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT. testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */, LOW_BMP_HEIGHT /* bitmapHeight */, @@ -161,13 +161,13 @@ public class ImageWallpaperTest extends SysuiTestCase { ImageWallpaper.CanvasEngine spyEngine = getSpyEngine(); spyEngine.onCreate(mSurfaceHolder); spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder); - assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1); + assertThat(mFakeExecutor.numPending()).isAtLeast(1); int n = 0; - while (mFakeBackgroundExecutor.numPending() >= 1) { + while (mFakeExecutor.numPending() >= 1) { n++; assertThat(n).isAtMost(10); - mFakeBackgroundExecutor.runNextReady(); + mFakeExecutor.runNextReady(); mFakeSystemClock.advanceTime(1000); } @@ -176,7 +176,7 @@ public class ImageWallpaperTest extends SysuiTestCase { } private ImageWallpaper createImageWallpaper() { - return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) { + return new ImageWallpaper(mFakeExecutor, mUserTracker) { @Override public Engine onCreateEngine() { return new CanvasEngine() { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt new file mode 100644 index 000000000000..4e435462be50 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.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.keyboard.data.repository + +import com.android.systemui.keyboard.shared.model.BacklightModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filterNotNull + +class FakeKeyboardRepository : KeyboardRepository { + + private val _keyboardConnected = MutableStateFlow(false) + override val keyboardConnected: Flow<Boolean> = _keyboardConnected + + private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null) + // filtering to make sure backlight doesn't have default initial value + override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull() + + fun setBacklight(state: BacklightModel) { + _backlightState.value = state + } + + fun setKeyboardConnected(connected: Boolean) { + _keyboardConnected.value = connected + } +} diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp index 180b611aa13b..2e0a9462ffbe 100644 --- a/packages/SystemUI/unfold/Android.bp +++ b/packages/SystemUI/unfold/Android.bp @@ -35,6 +35,7 @@ android_library { ], kotlincflags: ["-Xjvm-default=enable"], java_version: "1.8", + sdk_version: "current", min_sdk_version: "current", plugins: ["dagger2-compiler"], } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt index 068347cfe9d8..a07966823c81 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -19,8 +19,8 @@ package com.android.systemui.unfold import android.content.ContentResolver import android.content.Context import android.hardware.SensorManager +import android.hardware.display.DisplayManager import android.os.Handler -import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg @@ -61,7 +61,7 @@ interface UnfoldSharedComponent { @BindsInstance @UnfoldMain executor: Executor, @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor, @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, - @BindsInstance windowManager: IWindowManager, + @BindsInstance displayManager: DisplayManager, @BindsInstance contentResolver: ContentResolver = context.contentResolver ): UnfoldSharedComponent } @@ -84,8 +84,9 @@ interface RemoteUnfoldSharedComponent { @BindsInstance context: Context, @BindsInstance config: UnfoldTransitionConfig, @BindsInstance @UnfoldMain executor: Executor, + @BindsInstance @UnfoldMain handler: Handler, @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor, - @BindsInstance windowManager: IWindowManager, + @BindsInstance displayManager: DisplayManager, @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, ): RemoteUnfoldSharedComponent } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index 8eb79df55496..18399194434a 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -19,8 +19,8 @@ package com.android.systemui.unfold import android.content.Context import android.hardware.SensorManager +import android.hardware.display.DisplayManager import android.os.Handler -import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.updates.FoldProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider @@ -47,7 +47,7 @@ fun createUnfoldSharedComponent( mainExecutor: Executor, singleThreadBgExecutor: Executor, tracingTagPrefix: String, - windowManager: IWindowManager, + displayManager: DisplayManager, ): UnfoldSharedComponent = DaggerUnfoldSharedComponent.factory() .create( @@ -61,7 +61,7 @@ fun createUnfoldSharedComponent( mainExecutor, singleThreadBgExecutor, tracingTagPrefix, - windowManager, + displayManager, ) /** @@ -73,16 +73,18 @@ fun createRemoteUnfoldSharedComponent( context: Context, config: UnfoldTransitionConfig, mainExecutor: Executor, + mainHandler: Handler, singleThreadBgExecutor: Executor, tracingTagPrefix: String, - windowManager: IWindowManager, + displayManager: DisplayManager, ): RemoteUnfoldSharedComponent = DaggerRemoteUnfoldSharedComponent.factory() .create( context, config, mainExecutor, + mainHandler, singleThreadBgExecutor, - windowManager, + displayManager, tracingTagPrefix, ) diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt index d19b414cb963..28e493651137 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt @@ -16,7 +16,6 @@ package com.android.systemui.unfold.progress import android.os.Trace -import android.os.Trace.TRACE_TAG_APP import android.util.Log import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatPropertyCompat @@ -110,7 +109,7 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor( if (DEBUG) { Log.d(TAG, "onFoldUpdate = ${update.name()}") - Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update) + Trace.setCounter("fold_update", update.toLong()) } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index 82fd2258120a..d653fc7beff2 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -119,7 +119,7 @@ constructor( "lastHingeAngle: $lastHingeAngle, " + "lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition" ) - Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt()) + Trace.setCounter( "hinge_angle", angle.toLong()) } val currentDirection = diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt index 0cf8224d3a3f..ce8f1a178d05 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt @@ -17,36 +17,32 @@ package com.android.systemui.unfold.updates import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Handler import android.os.RemoteException -import android.view.IRotationWatcher -import android.view.IWindowManager -import android.view.Surface.Rotation import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.util.CallbackController -import java.util.concurrent.Executor import javax.inject.Inject /** - * Allows to subscribe to rotation changes. - * - * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while - * most of the times we want them in the main one. Updates are provided for the display associated + * Allows to subscribe to rotation changes. Updates are provided for the display associated * to [context]. */ class RotationChangeProvider @Inject constructor( - private val windowManagerInterface: IWindowManager, + private val displayManager: DisplayManager, private val context: Context, - @UnfoldMain private val mainExecutor: Executor, + @UnfoldMain private val mainHandler: Handler, ) : CallbackController<RotationChangeProvider.RotationListener> { private val listeners = mutableListOf<RotationListener>() - private val rotationWatcher = RotationWatcher() + private val displayListener = RotationDisplayListener() + private var lastRotation: Int? = null override fun addCallback(listener: RotationListener) { - mainExecutor.execute { + mainHandler.post { if (listeners.isEmpty()) { subscribeToRotation() } @@ -55,17 +51,18 @@ constructor( } override fun removeCallback(listener: RotationListener) { - mainExecutor.execute { + mainHandler.post { listeners -= listener if (listeners.isEmpty()) { unsubscribeToRotation() + lastRotation = null } } } private fun subscribeToRotation() { try { - windowManagerInterface.watchRotation(rotationWatcher, context.displayId) + displayManager.registerDisplayListener(displayListener, mainHandler) } catch (e: RemoteException) { throw e.rethrowFromSystemServer() } @@ -73,7 +70,7 @@ constructor( private fun unsubscribeToRotation() { try { - windowManagerInterface.removeRotationWatcher(rotationWatcher) + displayManager.unregisterDisplayListener(displayListener) } catch (e: RemoteException) { throw e.rethrowFromSystemServer() } @@ -82,12 +79,25 @@ constructor( /** Gets notified of rotation changes. */ fun interface RotationListener { /** Called once rotation changes. */ - fun onRotationChanged(@Rotation newRotation: Int) + fun onRotationChanged(newRotation: Int) } - private inner class RotationWatcher : IRotationWatcher.Stub() { - override fun onRotationChanged(rotation: Int) { - mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } } + private inner class RotationDisplayListener : DisplayManager.DisplayListener { + + override fun onDisplayChanged(displayId: Int) { + val display = context.display ?: return + + if (displayId == display.displayId) { + val currentRotation = display.rotation + if (lastRotation == null || lastRotation != currentRotation) { + listeners.forEach { it.onRotationChanged(currentRotation) } + lastRotation = currentRotation + } + } } + + override fun onDisplayAdded(displayId: Int) {} + + override fun onDisplayRemoved(displayId: Int) {} } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt index 06ca153b694b..ce5c5f91914b 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt @@ -79,10 +79,9 @@ constructor( companion object { fun ContentResolver.areAnimationsEnabled(): Boolean { val animationScale = - Settings.Global.getStringForUser( + Settings.Global.getString( this, Settings.Global.ANIMATOR_DURATION_SCALE, - this.userId ) ?.toFloatOrNull() ?: 1f diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index a3592166ba03..e159f18809c4 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -1635,7 +1635,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return false; } - if (event.isAccessibilityDataPrivate() + if (event.isAccessibilityDataSensitive() && (mFetchFlags & AccessibilityNodeInfo.FLAG_SERVICE_IS_ACCESSIBILITY_TOOL) == 0) { return false; } diff --git a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java index 86b5a12f3c47..fa30a6f419f9 100644 --- a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java +++ b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java @@ -53,6 +53,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.util.FeatureFlagUtils; import android.util.Log; import android.view.Display; import android.view.View; @@ -254,7 +255,7 @@ class FlashNotificationsController { broadcastFilter.addAction(ACTION_FLASH_NOTIFICATION_STOP_PREVIEW); mFlashBroadcastReceiver = new FlashBroadcastReceiver(); mContext.registerReceiver( - mFlashBroadcastReceiver, broadcastFilter, Context.RECEIVER_EXPORTED); + mFlashBroadcastReceiver, broadcastFilter, Context.RECEIVER_NOT_EXPORTED); final PowerManager powerManager = mContext.getSystemService(PowerManager.class); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG); @@ -342,10 +343,12 @@ class FlashNotificationsController { private void requestStartFlashNotification(FlashNotification flashNotification) { if (DEBUG) Log.d(LOG_TAG, "requestStartFlashNotification"); - mIsCameraFlashNotificationEnabled = Settings.System.getIntForUser( + boolean isFeatureOn = FeatureFlagUtils.isEnabled(mContext, + FeatureFlagUtils.SETTINGS_FLASH_NOTIFICATIONS); + mIsCameraFlashNotificationEnabled = isFeatureOn && Settings.System.getIntForUser( mContext.getContentResolver(), SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0, UserHandle.USER_CURRENT) != 0; - mIsScreenFlashNotificationEnabled = Settings.System.getIntForUser( + mIsScreenFlashNotificationEnabled = isFeatureOn && Settings.System.getIntForUser( mContext.getContentResolver(), SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0, UserHandle.USER_CURRENT) != 0; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 43b816bae651..61032dc7a59c 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -849,6 +849,32 @@ final class AutofillManagerServiceImpl } } + + /** + * Updates the last fill response when a view was entered. + */ + void logViewEntered(int sessionId, @Nullable Bundle clientState) { + synchronized (mLock) { + if (!isValidEventLocked("logViewEntered", sessionId)) { + return; + } + + if (mEventHistory.getEvents() != null) { + // Do not log this event more than once + for (Event event : mEventHistory.getEvents()) { + if (event.getType() == Event.TYPE_VIEW_REQUESTED_AUTOFILL) { + Slog.v(TAG, "logViewEntered: already logged TYPE_VIEW_REQUESTED_AUTOFILL"); + return; + } + } + } + + mEventHistory.addEvent( + new Event(Event.TYPE_VIEW_REQUESTED_AUTOFILL, null, clientState, null, + null, null, null, null, null, null, null)); + } + } + void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset, @Nullable Bundle clientState) { synchronized (mLock) { diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 598521f31ff5..4a12e3843972 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -442,6 +442,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private boolean mPreviouslyFillDialogPotentiallyStarted; /** + * Keeps track of if the user entered view, this is used to + * distinguish Fill Request that did not have user interaction + * with ones that did. + * + * This is set to true when entering view - after FillDialog FillRequest + * or on plain user tap. + */ + @NonNull + @GuardedBy("mLock") + private boolean mLogViewEntered; + + /** * Keeps the fill dialog trigger ids of the last response. This invalidates * the trigger ids of the previous response. */ @@ -1289,6 +1301,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED) .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags)); + mLogViewEntered = false; } /** @@ -1413,6 +1426,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mService.setLastResponse(id, response); + synchronized (mLock) { + if (mLogViewEntered) { + mLogViewEntered = false; + mService.logViewEntered(id, null); + } + } + + final long disableDuration = response.getDisableDuration(); final boolean autofillDisabled = disableDuration > 0; if (autofillDisabled) { @@ -3545,6 +3566,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } + synchronized (mLock) { + if (!mLogViewEntered) { + // If the current request is for FillDialog (preemptive) + // then this is the first time that the view is entered + // (mLogViewEntered == false) in this case, setLastResponse() + // has already been called, so just log here. + // If the current request is not and (mLogViewEntered == false) + // then the last session is being tracked (setLastResponse not called) + // so this calling logViewEntered will be a nop. + // Calling logViewEntered() twice will only log it once + // TODO(271181979): this is broken for multiple partitions + mService.logViewEntered(this.id, null); + } + + // If this is the first time view is entered for inline, the last + // session is still being tracked, so logViewEntered() needs + // to be delayed until setLastResponse is called. + // For fill dialog requests case logViewEntered is already called above + // so this will do nothing. Assumption: only one fill dialog per session + mLogViewEntered = true; + } + // Previously, fill request will only start whenever a view is entered. // With Fill Dialog, request starts prior to view getting entered. So, we can't end // the event at this moment, otherwise we will be wrongly attributing fill dialog diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index a35cae9dffda..542cc2f0a0a6 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -59,6 +59,8 @@ import android.companion.DeviceNotAssociatedException; import android.companion.IAssociationRequestCallback; import android.companion.ICompanionDeviceManager; import android.companion.IOnAssociationsChangedListener; +import android.companion.IOnMessageReceivedListener; +import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.content.ComponentName; import android.content.Context; @@ -232,7 +234,7 @@ public class CompanionDeviceManagerService extends SystemService { /* cdmService */this, mAssociationStore); mCompanionAppController = new CompanionApplicationController( context, mAssociationStore, mDevicePresenceMonitor); - mTransportManager = new CompanionTransportManager(context); + mTransportManager = new CompanionTransportManager(context, mAssociationStore); mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore, mSystemDataTransferRequestStore, mTransportManager); @@ -601,6 +603,37 @@ public class CompanionDeviceManagerService extends SystemService { } @Override + @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports") + public void addOnTransportsChangedListener(IOnTransportsChangedListener listener) { + mTransportManager.addListener(listener); + } + + @Override + @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports") + public void removeOnTransportsChangedListener(IOnTransportsChangedListener listener) { + mTransportManager.removeListener(listener); + } + + @Override + @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports") + public void sendMessage(int messageType, byte[] data, int[] associationIds) { + mTransportManager.sendMessage(messageType, data, associationIds); + } + + @Override + @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports") + public void addOnMessageReceivedListener(int messageType, + IOnMessageReceivedListener listener) { + mTransportManager.addListener(messageType, listener); + } + + @Override + public void removeOnMessageReceivedListener(int messageType, + IOnMessageReceivedListener listener) { + mTransportManager.removeListener(messageType, listener); + } + + @Override public void legacyDisassociate(String deviceMacAddress, String packageName, int userId) { Log.i(TAG, "legacyDisassociate() pkg=u" + userId + "/" + packageName + ", macAddress=" + deviceMacAddress); diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index 9f27f721ea83..f3a949d29ff8 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -23,6 +23,7 @@ import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVER import static android.content.ComponentName.createRelative; import static com.android.server.companion.Utils.prepareForIpc; +import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,6 +31,7 @@ import android.annotation.UserIdInt; import android.app.PendingIntent; import android.companion.AssociationInfo; import android.companion.DeviceNotAssociatedException; +import android.companion.IOnMessageReceivedListener; import android.companion.ISystemDataTransferCallback; import android.companion.datatransfer.PermissionSyncRequest; import android.companion.datatransfer.SystemDataTransferRequest; @@ -39,6 +41,7 @@ import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; @@ -91,7 +94,18 @@ public class SystemDataTransferProcessor { mAssociationStore = associationStore; mSystemDataTransferRequestStore = systemDataTransferRequestStore; mTransportManager = transportManager; - mTransportManager.setListener(this::onReceivePermissionRestore); + IOnMessageReceivedListener messageListener = new IOnMessageReceivedListener() { + @Override + public void onMessageReceived(int associationId, byte[] data) throws RemoteException { + onReceivePermissionRestore(data); + } + + @Override + public IBinder asBinder() { + return null; + } + }; + mTransportManager.addListener(MESSAGE_REQUEST_PERMISSION_RESTORE, messageListener); mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class); mExecutor = Executors.newSingleThreadExecutor(); } diff --git a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java index adaee757b96a..1559a3f8fdf8 100644 --- a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java +++ b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java @@ -35,7 +35,7 @@ import java.util.function.BiConsumer; /** * Helper class to perform attestation verification synchronously. */ -class AttestationVerifier { +public class AttestationVerifier { private static final long ATTESTATION_VERIFICATION_TIMEOUT_SECONDS = 10; // 10 seconds private static final String PARAM_OWNED_BY_SYSTEM = "android.key_owned_by_system"; diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java index 13dba84487e3..05b6022ce569 100644 --- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java +++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java @@ -110,7 +110,7 @@ public class SecureChannel { this(in, out, callback, null, new AttestationVerifier(context)); } - private SecureChannel( + public SecureChannel( final InputStream in, final OutputStream out, Callback callback, @@ -381,9 +381,10 @@ public class SecureChannel { private void exchangeAuthentication() throws IOException, GeneralSecurityException, BadHandleException, CryptoException { - if (mVerifier == null) { + if (mPreSharedKey != null) { exchangePreSharedKey(); - } else { + } + if (mVerifier != null) { exchangeAttestation(); } } diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java index 6a53adfeea9d..539020519f84 100644 --- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java +++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java @@ -19,23 +19,35 @@ package com.android.server.companion.transport; import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES; import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE; +import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PLATFORM_INFO; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.ActivityManagerInternal; +import android.companion.AssociationInfo; +import android.companion.IOnMessageReceivedListener; +import android.companion.IOnTransportsChangedListener; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Binder; import android.os.Build; +import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; +import com.android.server.companion.AssociationStore; import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; @@ -44,6 +56,9 @@ public class CompanionTransportManager { private static final String TAG = "CDM_CompanionTransportManager"; private static final boolean DEBUG = false; + private static final int SECURE_CHANNEL_AVAILABLE_SDK = Build.VERSION_CODES.UPSIDE_DOWN_CAKE; + private static final int NON_ANDROID = -1; + private boolean mSecureTransportEnabled = true; private static boolean isRequest(int message) { @@ -54,24 +69,98 @@ public class CompanionTransportManager { return (message & 0xFF000000) == 0x33000000; } - public interface Listener { - void onRequestPermissionRestore(byte[] data); - } - private final Context mContext; + private final AssociationStore mAssociationStore; + /** Association id -> Transport */ @GuardedBy("mTransports") private final SparseArray<Transport> mTransports = new SparseArray<>(); + @NonNull + private final RemoteCallbackList<IOnTransportsChangedListener> mTransportsListeners = + new RemoteCallbackList<>(); + /** Message type -> IOnMessageReceivedListener */ + @NonNull + private final SparseArray<IOnMessageReceivedListener> mMessageListeners = new SparseArray<>(); + @Nullable - private Listener mListener; + private Transport mTempTransport; - public CompanionTransportManager(Context context) { + public CompanionTransportManager(Context context, AssociationStore associationStore) { mContext = context; + mAssociationStore = associationStore; + } + + /** + * Add a listener to receive callbacks when a message is received for the message type + */ + @GuardedBy("mTransports") + public void addListener(int message, @NonNull IOnMessageReceivedListener listener) { + mMessageListeners.put(message, listener); + for (int i = 0; i < mTransports.size(); i++) { + mTransports.valueAt(i).addListener(message, listener); + } } - public void setListener(@NonNull Listener listener) { - mListener = listener; + /** + * Add a listener to receive callbacks when any of the transports is changed + */ + @GuardedBy("mTransports") + public void addListener(IOnTransportsChangedListener listener) { + Slog.i(TAG, "Registering OnTransportsChangedListener"); + mTransportsListeners.register(listener); + List<AssociationInfo> associations = new ArrayList<>(); + for (int i = 0; i < mTransports.size(); i++) { + AssociationInfo association = mAssociationStore.getAssociationById( + mTransports.keyAt(i)); + if (association != null) { + associations.add(association); + } + } + mTransportsListeners.broadcast(listener1 -> { + // callback to the current listener with all the associations of the transports + // immediately + if (listener1 == listener) { + try { + listener.onTransportsChanged(associations); + } catch (RemoteException ignored) { + } + } + }); + } + + /** + * Remove the listener for receiving callbacks when any of the transports is changed + */ + public void removeListener(IOnTransportsChangedListener listener) { + mTransportsListeners.unregister(listener); + } + + /** + * Remove the listener to stop receiving calbacks when a message is received for the given type + */ + public void removeListener(int messageType, IOnMessageReceivedListener listener) { + mMessageListeners.remove(messageType); + } + + /** + * Send a message to remote devices through the transports + */ + @GuardedBy("mTransports") + public void sendMessage(int message, byte[] data, int[] associationIds) { + Slog.i(TAG, "Sending message 0x" + Integer.toHexString(message) + + " data length " + data.length); + for (int i = 0; i < associationIds.length; i++) { + if (mTransports.contains(associationIds[i])) { + try { + mTransports.get(associationIds[i]).sendMessage(message, data); + } catch (IOException e) { + Slog.e(TAG, "Failed to send message 0x" + Integer.toHexString(message) + + " data length " + data.length + " to association " + + associationIds[i]); + } + } + } } /** @@ -105,15 +194,9 @@ public class CompanionTransportManager { detachSystemDataTransport(packageName, userId, associationId); } - final Transport transport; - if (isSecureTransportEnabled(associationId)) { - transport = new SecureTransport(associationId, fd, mContext, mListener); - } else { - transport = new RawTransport(associationId, fd, mContext, mListener); - } + initializeTransport(associationId, fd); - transport.start(); - mTransports.put(associationId, transport); + notifyOnTransportsChanged(); } } @@ -125,7 +208,116 @@ public class CompanionTransportManager { mTransports.delete(associationId); transport.stop(); } + + notifyOnTransportsChanged(); + } + } + + @GuardedBy("mTransports") + private void notifyOnTransportsChanged() { + List<AssociationInfo> associations = new ArrayList<>(); + for (int i = 0; i < mTransports.size(); i++) { + AssociationInfo association = mAssociationStore.getAssociationById( + mTransports.keyAt(i)); + if (association != null) { + associations.add(association); + } } + mTransportsListeners.broadcast(listener -> { + try { + listener.onTransportsChanged(associations); + } catch (RemoteException ignored) { + } + }); + } + + @GuardedBy("mTransports") + private void initializeTransport(int associationId, ParcelFileDescriptor fd) { + Slog.i(TAG, "Initializing transport"); + if (!isSecureTransportEnabled()) { + Transport transport = new RawTransport(associationId, fd, mContext); + addMessageListenersToTransport(transport); + transport.start(); + mTransports.put(associationId, transport); + Slog.i(TAG, "RawTransport is created"); + return; + } + + // Exchange platform info to decide which transport should be created + mTempTransport = new RawTransport(associationId, fd, mContext); + addMessageListenersToTransport(mTempTransport); + IOnMessageReceivedListener listener = new IOnMessageReceivedListener() { + @Override + public void onMessageReceived(int associationId, byte[] data) throws RemoteException { + synchronized (mTransports) { + onPlatformInfoReceived(associationId, data); + } + } + + @Override + public IBinder asBinder() { + return null; + } + }; + mTempTransport.addListener(MESSAGE_REQUEST_PLATFORM_INFO, listener); + mTempTransport.start(); + + int sdk = Build.VERSION.SDK_INT; + String release = Build.VERSION.RELEASE; + // data format: | SDK_INT (int) | release length (int) | release | + final ByteBuffer data = ByteBuffer.allocate(4 + 4 + release.getBytes().length) + .putInt(sdk) + .putInt(release.getBytes().length) + .put(release.getBytes()); + + // TODO: it should check if preSharedKey is given + try { + mTempTransport.sendMessage(MESSAGE_REQUEST_PLATFORM_INFO, data.array()); + } catch (IOException e) { + Slog.e(TAG, "Failed to exchange platform info"); + } + } + + /** + * Depending on the remote platform info to decide which transport should be created + */ + @GuardedBy("CompanionTransportManager.this.mTransports") + private void onPlatformInfoReceived(int associationId, byte[] data) { + if (mTempTransport.getAssociationId() != associationId) { + return; + } + // TODO: it should check if preSharedKey is given + + ByteBuffer buffer = ByteBuffer.wrap(data); + int remoteSdk = buffer.getInt(); + byte[] remoteRelease = new byte[buffer.getInt()]; + buffer.get(remoteRelease); + + Slog.i(TAG, "Remote device SDK: " + remoteSdk + ", release:" + new String(remoteRelease)); + + Transport transport = mTempTransport; + mTempTransport = null; + + int sdk = Build.VERSION.SDK_INT; + String release = Build.VERSION.RELEASE; + if (remoteSdk == NON_ANDROID) { + // TODO: pass in a real preSharedKey + transport = new SecureTransport(transport.getAssociationId(), transport.getFd(), + mContext, null, null); + } else if (sdk < SECURE_CHANNEL_AVAILABLE_SDK + || remoteSdk < SECURE_CHANNEL_AVAILABLE_SDK) { + // TODO: depending on the release version, either + // 1) using a RawTransport for old T versions + // 2) or an Ukey2 handshaked transport for UKey2 backported T versions + } else { + Slog.i(TAG, "Creating a secure channel"); + transport = new SecureTransport(transport.getAssociationId(), transport.getFd(), + mContext); + addMessageListenersToTransport(transport); + transport.start(); + } + mTransports.put(transport.getAssociationId(), transport); + // Doesn't need to notifyTransportsChanged here, it'll be done in attachSystemDataTransport } public Future<?> requestPermissionRestore(int associationId, byte[] data) { @@ -134,7 +326,6 @@ public class CompanionTransportManager { if (transport == null) { return CompletableFuture.failedFuture(new IOException("Missing transport")); } - return transport.requestForResponse(MESSAGE_REQUEST_PERMISSION_RESTORE, data); } } @@ -146,10 +337,15 @@ public class CompanionTransportManager { this.mSecureTransportEnabled = enabled; } - private boolean isSecureTransportEnabled(int associationId) { + private boolean isSecureTransportEnabled() { boolean enabled = !Build.IS_DEBUGGABLE || mSecureTransportEnabled; - // TODO: version comparison logic return enabled; } + + private void addMessageListenersToTransport(Transport transport) { + for (int i = 0; i < mMessageListeners.size(); i++) { + transport.addListener(mMessageListeners.keyAt(i), mMessageListeners.valueAt(i)); + } + } } diff --git a/services/companion/java/com/android/server/companion/transport/CryptoManager.java b/services/companion/java/com/android/server/companion/transport/CryptoManager.java index b08354afc8ad..a15939e52936 100644 --- a/services/companion/java/com/android/server/companion/transport/CryptoManager.java +++ b/services/companion/java/com/android/server/companion/transport/CryptoManager.java @@ -16,51 +16,51 @@ package com.android.server.companion.transport; -import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.KeyProperties; import android.util.Slog; -import java.io.IOException; import java.nio.ByteBuffer; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableEntryException; -import java.security.cert.CertificateException; +import java.util.Arrays; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; -import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; /** - * This class can be used to encrypt and decrypt bytes using Android Cryptography + * This class uses Java Cryptography to encrypt and decrypt messages */ public class CryptoManager { private static final String TAG = "CDM_CryptoManager"; + private static final int SECRET_KEY_LENGTH = 32; + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding"; - private static final String KEY_STORE_ALIAS = "cdm_secret"; - private static final String ALGORITHM = KeyProperties.KEY_ALGORITHM_AES; - private static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC; - private static final String PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7; - private static final String TRANSFORMATION = ALGORITHM + "/" + BLOCK_MODE + "/" + PADDING; + private final byte[] mPreSharedKey; + private Cipher mEncryptCipher; + private Cipher mDecryptCipher; - private final KeyStore mKeyStore; + private SecretKey mSecretKey; - public CryptoManager() { - // Initialize KeyStore + public CryptoManager(byte[] preSharedKey) { + if (preSharedKey == null) { + mPreSharedKey = Arrays.copyOf(new byte[0], SECRET_KEY_LENGTH); + } else { + mPreSharedKey = Arrays.copyOf(preSharedKey, SECRET_KEY_LENGTH); + } + mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM); try { - mKeyStore = KeyStore.getInstance("AndroidKeyStore"); - mKeyStore.load(null); - } catch (KeyStoreException | IOException | NoSuchAlgorithmException - | CertificateException e) { - throw new RuntimeException(e); + mEncryptCipher = Cipher.getInstance(TRANSFORMATION); + mEncryptCipher.init(Cipher.ENCRYPT_MODE, mSecretKey); + mDecryptCipher = Cipher.getInstance(TRANSFORMATION); + } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { + Slog.e(TAG, e.getMessage()); } } @@ -69,21 +69,19 @@ public class CryptoManager { */ public byte[] encrypt(byte[] input) { try { - // Encrypt using Cipher - Cipher encryptCipher = Cipher.getInstance(TRANSFORMATION); - encryptCipher.init(Cipher.ENCRYPT_MODE, getKey()); - byte[] encryptedBytes = encryptCipher.doFinal(input); + if (mEncryptCipher == null) { + return null; + } - // Write to bytes + byte[] encryptedBytes = mEncryptCipher.doFinal(input); ByteBuffer buffer = ByteBuffer.allocate( - 4 + encryptCipher.getIV().length + 4 + encryptedBytes.length) - .putInt(encryptCipher.getIV().length) - .put(encryptCipher.getIV()) + 4 + mEncryptCipher.getIV().length + 4 + encryptedBytes.length) + .putInt(mEncryptCipher.getIV().length) + .put(mEncryptCipher.getIV()) .putInt(encryptedBytes.length) .put(encryptedBytes); return buffer.array(); - } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | IllegalBlockSizeException | BadPaddingException e) { + } catch (IllegalBlockSizeException | BadPaddingException e) { Slog.e(TAG, e.getMessage()); return null; } @@ -99,45 +97,20 @@ public class CryptoManager { byte[] encryptedBytes = new byte[buffer.getInt()]; buffer.get(encryptedBytes); try { - Cipher decryptCipher = Cipher.getInstance(TRANSFORMATION); - decryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv)); - return decryptCipher.doFinal(encryptedBytes); - } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | InvalidAlgorithmParameterException | IllegalBlockSizeException - | BadPaddingException e) { + mDecryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv)); + return mDecryptCipher.doFinal(encryptedBytes); + } catch (InvalidKeyException | InvalidAlgorithmParameterException + | IllegalBlockSizeException | BadPaddingException e) { Slog.e(TAG, e.getMessage()); return null; } } private SecretKey getKey() { - try { - KeyStore.Entry keyEntry = mKeyStore.getEntry(KEY_STORE_ALIAS, null); - if (keyEntry instanceof KeyStore.SecretKeyEntry - && ((KeyStore.SecretKeyEntry) keyEntry).getSecretKey() != null) { - return ((KeyStore.SecretKeyEntry) keyEntry).getSecretKey(); - } else { - return createKey(); - } - } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) { - throw new RuntimeException(e); - } - } - - private SecretKey createKey() { - try { - KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); - keyGenerator.init( - new KeyGenParameterSpec.Builder(KEY_STORE_ALIAS, - KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(BLOCK_MODE) - .setEncryptionPaddings(PADDING) - .setUserAuthenticationRequired(false) - .setRandomizedEncryptionRequired(true) - .build()); - return keyGenerator.generateKey(); - } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { - throw new RuntimeException(e); + if (mSecretKey != null) { + return mSecretKey; } + mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM); + return mSecretKey; } } diff --git a/services/companion/java/com/android/server/companion/transport/RawTransport.java b/services/companion/java/com/android/server/companion/transport/RawTransport.java index 7c0c7cf7ac68..4060f6efe0ca 100644 --- a/services/companion/java/com/android/server/companion/transport/RawTransport.java +++ b/services/companion/java/com/android/server/companion/transport/RawTransport.java @@ -21,8 +21,6 @@ import android.content.Context; import android.os.ParcelFileDescriptor; import android.util.Slog; -import com.android.server.companion.transport.CompanionTransportManager.Listener; - import libcore.io.IoUtils; import libcore.io.Streams; @@ -32,8 +30,8 @@ import java.nio.ByteBuffer; class RawTransport extends Transport { private volatile boolean mStopped; - RawTransport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) { - super(associationId, fd, context, listener); + RawTransport(int associationId, ParcelFileDescriptor fd, Context context) { + super(associationId, fd, context); } @Override @@ -64,7 +62,7 @@ class RawTransport extends Transport { protected void sendMessage(int message, int sequence, @NonNull byte[] data) throws IOException { if (DEBUG) { - Slog.d(TAG, "Sending message 0x" + Integer.toHexString(message) + Slog.e(TAG, "Sending message 0x" + Integer.toHexString(message) + " sequence " + sequence + " length " + data.length + " to association " + mAssociationId); } diff --git a/services/companion/java/com/android/server/companion/transport/SecureTransport.java b/services/companion/java/com/android/server/companion/transport/SecureTransport.java index 4194130f7e84..cca08435c0a5 100644 --- a/services/companion/java/com/android/server/companion/transport/SecureTransport.java +++ b/services/companion/java/com/android/server/companion/transport/SecureTransport.java @@ -21,8 +21,8 @@ import android.content.Context; import android.os.ParcelFileDescriptor; import android.util.Slog; +import com.android.server.companion.securechannel.AttestationVerifier; import com.android.server.companion.securechannel.SecureChannel; -import com.android.server.companion.transport.CompanionTransportManager.Listener; import java.io.IOException; import java.nio.ByteBuffer; @@ -37,14 +37,17 @@ class SecureTransport extends Transport implements SecureChannel.Callback { private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100); - SecureTransport(int associationId, - ParcelFileDescriptor fd, - Context context, - Listener listener) { - super(associationId, fd, context, listener); + SecureTransport(int associationId, ParcelFileDescriptor fd, Context context) { + super(associationId, fd, context); mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, context); } + SecureTransport(int associationId, ParcelFileDescriptor fd, Context context, + byte[] preSharedKey, AttestationVerifier verifier) { + super(associationId, fd, context); + mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, preSharedKey, verifier); + } + @Override public void start() { mSecureChannel.start(); diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java index 923d4243a34c..d69ce8909c74 100644 --- a/services/companion/java/com/android/server/companion/transport/Transport.java +++ b/services/companion/java/com/android/server/companion/transport/Transport.java @@ -17,31 +17,39 @@ package com.android.server.companion.transport; import android.annotation.NonNull; +import android.companion.IOnMessageReceivedListener; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.server.companion.transport.CompanionTransportManager.Listener; import libcore.util.EmptyArray; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; -abstract class Transport { +/** + * This class represents the channel established between two devices. + */ +public abstract class Transport { protected static final String TAG = "CDM_CompanionTransport"; protected static final boolean DEBUG = Build.IS_DEBUGGABLE; static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN - static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES + public static final int MESSAGE_REQUEST_PLATFORM_INFO = 0x63807073; // ?PFI + public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS + public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC static final int MESSAGE_RESPONSE_FAILURE = 0x33706573; // !FAI @@ -49,11 +57,19 @@ abstract class Transport { protected static final int HEADER_LENGTH = 12; protected final int mAssociationId; + protected final ParcelFileDescriptor mFd; protected final InputStream mRemoteIn; protected final OutputStream mRemoteOut; protected final Context mContext; - private final Listener mListener; + /** + * Message type -> Listener + * + * For now, the transport only supports 1 listener for each message type. If there's a need in + * the future to allow multiple listeners to receive callbacks for the same message type, the + * value of the map can be a list. + */ + private final Map<Integer, IOnMessageReceivedListener> mListeners; private static boolean isRequest(int message) { return (message & 0xFF000000) == 0x63000000; @@ -68,16 +84,43 @@ abstract class Transport { new SparseArray<>(); protected final AtomicInteger mNextSequence = new AtomicInteger(); - Transport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) { - this.mAssociationId = associationId; - this.mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd); - this.mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - this.mContext = context; - this.mListener = listener; + Transport(int associationId, ParcelFileDescriptor fd, Context context) { + mAssociationId = associationId; + mFd = fd; + mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd); + mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + mContext = context; + mListeners = new HashMap<>(); + } + + /** + * Add a listener when a message is received for the message type + * @param message Message type + * @param listener Execute when a message with the type is received + */ + public void addListener(int message, IOnMessageReceivedListener listener) { + mListeners.put(message, listener); + } + + public int getAssociationId() { + return mAssociationId; + } + + protected ParcelFileDescriptor getFd() { + return mFd; } public abstract void start(); public abstract void stop(); + protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data) + throws IOException; + + /** + * Send a message + */ + public void sendMessage(int message, @NonNull byte[] data) throws IOException { + sendMessage(message, mNextSequence.incrementAndGet(), data); + } public Future<byte[]> requestForResponse(int message, byte[] data) { if (DEBUG) Slog.d(TAG, "Requesting for response"); @@ -99,9 +142,6 @@ abstract class Transport { return pending; } - protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data) - throws IOException; - protected final void handleMessage(int message, int sequence, @NonNull byte[] data) throws IOException { if (DEBUG) { @@ -130,6 +170,12 @@ abstract class Transport { sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data); break; } + case MESSAGE_REQUEST_PLATFORM_INFO: + case MESSAGE_REQUEST_CONTEXT_SYNC: { + callback(message, data); + sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE); + break; + } case MESSAGE_REQUEST_PERMISSION_RESTORE: { if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH) && !Build.isDebuggable()) { @@ -138,7 +184,7 @@ abstract class Transport { break; } try { - mListener.onRequestPermissionRestore(data); + callback(message, data); sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE); } catch (Exception e) { Slog.w(TAG, "Failed to restore permissions"); @@ -154,6 +200,18 @@ abstract class Transport { } } + private void callback(int message, byte[] data) { + if (mListeners.containsKey(message)) { + try { + mListeners.get(message).onMessageReceived(getAssociationId(), data); + Slog.i(TAG, "Message 0x" + Integer.toHexString(message) + + " is received from associationId " + mAssociationId + + ", sending data length " + data.length + " to the listener."); + } catch (RemoteException ignored) { + } + } + } + private void processResponse(int message, int sequence, byte[] data) { final CompletableFuture<byte[]> future; synchronized (mPendingRequests) { diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index e52f1d9c61db..34033e225b80 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -16,7 +16,6 @@ package com.android.server.companion.virtual; -import static android.companion.virtual.VirtualDeviceParams.RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS; import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; @@ -29,7 +28,6 @@ import android.app.compat.CompatChanges; import android.companion.virtual.VirtualDeviceManager.ActivityListener; import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.VirtualDeviceParams.ActivityPolicy; -import android.companion.virtual.VirtualDeviceParams.RecentsPolicy; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.ComponentName; @@ -136,9 +134,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners = new ArraySet<>(); @Nullable private final SecureWindowCallback mSecureWindowCallback; - @Nullable private final List<String> mDisplayCategories; - @RecentsPolicy - private final int mDefaultRecentsPolicy; + @Nullable private final Set<String> mDisplayCategories; + + private final boolean mShowTasksInHostDeviceRecents; /** * Creates a window policy controller that is generic to the different use cases of virtual @@ -166,7 +164,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController * virtual display. * @param intentListenerCallback Callback that is called to intercept intents when matching * passed in filters. - * @param defaultRecentsPolicy a policy to indicate how to handle activities in recents. + * @param showTasksInHostDeviceRecents whether to show activities in recents on the host device. */ public GenericWindowPolicyController(int windowFlags, int systemWindowFlags, @NonNull ArraySet<UserHandle> allowedUsers, @@ -180,8 +178,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @NonNull ActivityBlockedCallback activityBlockedCallback, @NonNull SecureWindowCallback secureWindowCallback, @NonNull IntentListenerCallback intentListenerCallback, - @NonNull List<String> displayCategories, - @RecentsPolicy int defaultRecentsPolicy) { + @NonNull Set<String> displayCategories, + boolean showTasksInHostDeviceRecents) { super(); mAllowedUsers = allowedUsers; mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations); @@ -196,7 +194,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController mSecureWindowCallback = secureWindowCallback; mIntentListenerCallback = intentListenerCallback; mDisplayCategories = displayCategories; - mDefaultRecentsPolicy = defaultRecentsPolicy; + mShowTasksInHostDeviceRecents = showTasksInHostDeviceRecents; } /** @@ -337,7 +335,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Override public boolean canShowTasksInHostDeviceRecents() { - return (mDefaultRecentsPolicy & RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS) != 0; + return mShowTasksInHostDeviceRecents; } @Override diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java index 864fe0f5edc1..7df0d861dc22 100644 --- a/services/companion/java/com/android/server/companion/virtual/SensorController.java +++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java @@ -99,6 +99,9 @@ public class SensorController { private int createSensorInternal(IBinder sensorToken, VirtualSensorConfig config) throws SensorCreationException { + if (config.getType() <= 0) { + throw new SensorCreationException("Received an invalid virtual sensor type."); + } final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId, config.getType(), config.getName(), config.getVendor() == null ? "" : config.getVendor(), config.getFlags(), diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index ee1b1fd4a500..b338d89a0169 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -97,6 +97,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; @@ -830,7 +831,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } private GenericWindowPolicyController createWindowPolicyController( - @NonNull List<String> displayCategories) { + @NonNull Set<String> displayCategories) { final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(FLAG_SECURE, SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, @@ -846,7 +847,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub this::onSecureWindowShown, this::shouldInterceptIntent, displayCategories, - mParams.getDefaultRecentsPolicy()); + mParams.getDevicePolicy( + VirtualDeviceParams.POLICY_TYPE_RECENTS) + == VirtualDeviceParams.DEVICE_POLICY_DEFAULT); gwpc.registerRunningAppsChangedListener(/* listener= */ this); return gwpc; } diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java index 17ef9a232401..c6f63dd73a25 100644 --- a/services/core/java/android/os/BatteryStatsInternal.java +++ b/services/core/java/android/os/BatteryStatsInternal.java @@ -38,11 +38,13 @@ public abstract class BatteryStatsInternal { public static final int CPU_WAKEUP_SUBSYSTEM_UNKNOWN = -1; public static final int CPU_WAKEUP_SUBSYSTEM_ALARM = 1; + public static final int CPU_WAKEUP_SUBSYSTEM_WIFI = 2; /** @hide */ @IntDef(prefix = {"CPU_WAKEUP_SUBSYSTEM_"}, value = { CPU_WAKEUP_SUBSYSTEM_UNKNOWN, CPU_WAKEUP_SUBSYSTEM_ALARM, + CPU_WAKEUP_SUBSYSTEM_WIFI, }) @Retention(RetentionPolicy.SOURCE) @interface CpuWakeupSubsystem { diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java index 2992bf92e0a6..3ecf93328219 100644 --- a/services/core/java/com/android/server/BinaryTransparencyService.java +++ b/services/core/java/com/android/server/BinaryTransparencyService.java @@ -34,7 +34,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApexStagedEvent; import android.content.pm.ApplicationInfo; -import android.content.pm.Checksum; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.IPackageManagerNative; import android.content.pm.IStagedApexObserver; @@ -117,14 +116,17 @@ public class BinaryTransparencyService extends SystemService { @VisibleForTesting static final String BINARY_HASH_ERROR = "SHA256HashError"; - static final int MEASURE_APEX_AND_MODULES = 1; - static final int MEASURE_PRELOADS = 2; - static final int MEASURE_NEW_MBAS = 3; - static final long RECORD_MEASUREMENTS_COOLDOWN_MS = 24 * 60 * 60 * 1000; static final String APEX_PRELOAD_LOCATION_ERROR = "could-not-be-determined"; + // Copy from the atom. Consistent for both ApexInfoGathered and MobileBundledAppInfoGathered. + static final int DIGEST_ALGORITHM_UNKNOWN = 0; + static final int DIGEST_ALGORITHM_CHUNKED_SHA256 = 1; + static final int DIGEST_ALGORITHM_CHUNKED_SHA512 = 2; + static final int DIGEST_ALGORITHM_VERITY_CHUNKED_SHA256 = 3; + static final int DIGEST_ALGORITHM_SHA256 = 4; + // used for indicating any type of error during MBA measurement static final int MBA_STATUS_ERROR = 0; // used for indicating factory condition preloads @@ -226,9 +228,9 @@ public class BinaryTransparencyService extends SystemService { appInfo.mbaStatus = mbaStatus; // Only digest and split name are different between splits. - Checksum checksum = measureApk(split.getPath()); - appInfo.digest = checksum.getValue(); - appInfo.digestAlgorithm = checksum.getType(); + Digest digest = measureApk(split.getPath()); + appInfo.digest = digest.value; + appInfo.digestAlgorithm = digest.algorithm; results.add(appInfo); } @@ -260,10 +262,9 @@ public class BinaryTransparencyService extends SystemService { * Perform basic measurement (i.e. content digest) on a given APK. * * @param apkPath The APK (or APEX, since it's also an APK) file to be measured. - * @return a {@link android.content.pm.Checksum} with preferred digest algorithm type and - * the checksum. + * @return a {@link #Digest} with preferred digest algorithm type and the value. */ - private @Nullable Checksum measureApk(@NonNull String apkPath) { + private @Nullable Digest measureApk(@NonNull String apkPath) { // compute content digest Map<Integer, byte[]> contentDigests = computeApkContentDigest(apkPath); if (contentDigests == null) { @@ -274,20 +275,20 @@ public class BinaryTransparencyService extends SystemService { // And only one of them will be available per package. if (contentDigests.containsKey( ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) { - return new Checksum( - Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, + return new Digest( + DIGEST_ALGORITHM_CHUNKED_SHA256, contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)); } else if (contentDigests.containsKey( ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) { - return new Checksum( - Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512, + return new Digest( + DIGEST_ALGORITHM_CHUNKED_SHA512, contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)); } } // When something went wrong, fall back to simple sha256. byte[] digest = PackageUtils.computeSha256DigestForLargeFileAsBytes(apkPath, PackageUtils.createLargeFileBuffer()); - return new Checksum(Checksum.TYPE_WHOLE_SHA256, digest); + return new Digest(DIGEST_ALGORITHM_SHA256, digest); } @@ -350,7 +351,7 @@ public class BinaryTransparencyService extends SystemService { // lastly measure all newly installed MBAs List<IBinaryTransparencyService.AppInfo> allMbaInfo = collectAllSilentInstalledMbaInfo(packagesMeasured); - for (IBinaryTransparencyService.AppInfo appInfo : allUpdatedPreloadInfo) { + for (IBinaryTransparencyService.AppInfo appInfo : allMbaInfo) { packagesMeasured.putBoolean(appInfo.packageName, true); writeAppInfoToLog(appInfo); } @@ -381,7 +382,7 @@ public class BinaryTransparencyService extends SystemService { Slog.w(TAG, "Skipping the missing APK in " + pkg.getPath()); continue; } - Checksum apexChecksum = measureApk(pkg.getPath()); + Digest apexChecksum = measureApk(pkg.getPath()); if (apexChecksum == null) { Slog.w(TAG, "Skipping the missing APEX in " + pkg.getPath()); continue; @@ -390,8 +391,8 @@ public class BinaryTransparencyService extends SystemService { var apexInfo = new IBinaryTransparencyService.ApexInfo(); apexInfo.packageName = packageState.getPackageName(); apexInfo.longVersion = packageState.getVersionCode(); - apexInfo.digest = apexChecksum.getValue(); - apexInfo.digestAlgorithm = apexChecksum.getType(); + apexInfo.digest = apexChecksum.value; + apexInfo.digestAlgorithm = apexChecksum.algorithm; apexInfo.signerDigests = computePackageSignerSha256Digests(packageState.getSigningInfo()); @@ -1691,4 +1692,14 @@ public class BinaryTransparencyService extends SystemService { } return slice.getList(); } + + private static class Digest { + public int algorithm; + public byte[] value; + + Digest(int algorithm, byte[] value) { + this.algorithm = algorithm; + this.value = value; + } + } } diff --git a/services/core/java/com/android/server/LogMteState.java b/services/core/java/com/android/server/LogMteState.java new file mode 100644 index 000000000000..410dd8339b30 --- /dev/null +++ b/services/core/java/com/android/server/LogMteState.java @@ -0,0 +1,53 @@ +/* + * 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; + +import android.app.StatsManager; +import android.content.Context; +import android.util.StatsEvent; + +import com.android.internal.os.BackgroundThread; +import com.android.internal.os.Zygote; +import com.android.internal.util.FrameworkStatsLog; + +import java.util.List; + +public class LogMteState { + public static void register(Context context) { + context.getSystemService(StatsManager.class) + .setPullAtomCallback( + FrameworkStatsLog.MTE_STATE, + null, // use default PullAtomMetadata values + BackgroundThread.getExecutor(), + new StatsManager.StatsPullAtomCallback() { + @Override + public int onPullAtom(int atomTag, List<StatsEvent> data) { + if (atomTag != FrameworkStatsLog.MTE_STATE) { + throw new UnsupportedOperationException( + "Unknown tagId=" + atomTag); + } + data.add( + FrameworkStatsLog.buildStatsEvent( + FrameworkStatsLog.MTE_STATE, + Zygote.nativeSupportsMemoryTagging() + ? FrameworkStatsLog.MTE_STATE__STATE__ON + : FrameworkStatsLog.MTE_STATE__STATE__OFF)); + return StatsManager.PULL_SUCCESS; + } + }); + } +} diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index c5b0f0509c2b..c3dda71fdaaa 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -23,6 +23,18 @@ "file_patterns": ["NotificationManagerService\\.java"] }, { + "name": "CtsScopedStorageCoreHostTest", + "file_patterns": ["StorageManagerService\\.java"] + }, + { + "name": "CtsScopedStorageHostTest", + "file_patterns": ["StorageManagerService\\.java"] + }, + { + "name": "CtsScopedStorageDeviceOnlyTest", + "file_patterns": ["StorageManagerService\\.java"] + }, + { "name": "FrameworksMockingServicesTests", "options": [ { @@ -63,18 +75,6 @@ ], "presubmit-large": [ { - "name": "CtsScopedStorageCoreHostTest", - "file_patterns": ["StorageManagerService\\.java"] - }, - { - "name": "CtsScopedStorageHostTest", - "file_patterns": ["StorageManagerService\\.java"] - }, - { - "name": "CtsScopedStorageDeviceOnlyTest", - "file_patterns": ["StorageManagerService\\.java"] - }, - { "name": "CtsContentTestCases", "options": [ { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index aaa376afa139..bffa3dd79754 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1672,57 +1672,62 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - synchronized (mRecords) { - String str = "notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + phoneId - + " state=" + state; - if (VDBG) { - log(str); - } - mLocalLog.log(str); - // for service state updates, don't notify clients when subId is invalid. This prevents - // us from sending incorrect notifications like b/133140128 - // In the future, we can remove this logic for every notification here and add a - // callback so listeners know when their PhoneStateListener's subId becomes invalid, but - // for now we use the simplest fix. - if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) { - mServiceState[phoneId] = state; + final long callingIdentity = Binder.clearCallingIdentity(); + try { + synchronized (mRecords) { + String str = "notifyServiceStateForSubscriber: subId=" + subId + " phoneId=" + + phoneId + " state=" + state; + if (VDBG) { + log(str); + } + mLocalLog.log(str); + // for service state updates, don't notify clients when subId is invalid. This + // prevents us from sending incorrect notifications like b/133140128 + // In the future, we can remove this logic for every notification here and add a + // callback so listeners know when their PhoneStateListener's subId becomes invalid, + // but for now we use the simplest fix. + if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) { + mServiceState[phoneId] = state; - for (Record r : mRecords) { - if (VDBG) { - log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId - + " phoneId=" + phoneId + " state=" + state); - } - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_SERVICE_STATE_CHANGED) - && idMatch(r, subId, phoneId)) { + for (Record r : mRecords) { + if (VDBG) { + log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId + + " phoneId=" + phoneId + " state=" + state); + } + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_SERVICE_STATE_CHANGED) + && idMatch(r, subId, phoneId)) { - try { - ServiceState stateToSend; - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - stateToSend = new ServiceState(state); - } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { - stateToSend = state.createLocationInfoSanitizedCopy(false); - } else { - stateToSend = state.createLocationInfoSanitizedCopy(true); - } - if (DBG) { - log("notifyServiceStateForSubscriber: callback.onSSC r=" + r - + " subId=" + subId + " phoneId=" + phoneId - + " state=" + stateToSend); + try { + ServiceState stateToSend; + if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + stateToSend = new ServiceState(state); + } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { + stateToSend = state.createLocationInfoSanitizedCopy(false); + } else { + stateToSend = state.createLocationInfoSanitizedCopy(true); + } + if (DBG) { + log("notifyServiceStateForSubscriber: callback.onSSC r=" + r + + " subId=" + subId + " phoneId=" + phoneId + + " state=" + stateToSend); + } + r.callback.onServiceStateChanged(stateToSend); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); } - r.callback.onServiceStateChanged(stateToSend); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); } } + } else { + log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId + + " or subId=" + subId); } - } else { - log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId - + " or subId=" + subId); + handleRemoveListLocked(); } - handleRemoveListLocked(); + broadcastServiceStateChanged(state, phoneId, subId); + } finally { + Binder.restoreCallingIdentity(callingIdentity); } - broadcastServiceStateChanged(state, phoneId, subId); } public void notifySimActivationStateChangedForPhoneId(int phoneId, int subId, @@ -3508,13 +3513,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { public static final String ACTION_SIGNAL_STRENGTH_CHANGED = "android.intent.action.SIG_STR"; private void broadcastServiceStateChanged(ServiceState state, int phoneId, int subId) { - final long ident = Binder.clearCallingIdentity(); try { mBatteryStats.notePhoneState(state.getState()); } catch (RemoteException re) { // Can't do much - } finally { - Binder.restoreCallingIdentity(ident); } // Send the broadcast exactly once to all possible disjoint sets of apps. @@ -3531,8 +3533,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not // READ_PHONE_STATE - if (Binder.withCleanCallingIdentity(() -> - LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) { + if (LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId())) { Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f90a3ce76e71..24c9e0f55ab9 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2092,6 +2092,17 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + if (r.mAllowStartForeground == REASON_DENIED) { + Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + + " BFSL DENIED."); + } else { + if (DEBUG_SHORT_SERVICE) { + Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + + " BFSL Allowed: " + + PowerExemptionManager.reasonCodeToString( + r.mAllowStartForeground)); + } + } final boolean fgsStartAllowed = !isBgFgsRestrictionEnabledForService diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a1f7445d4142..4ba6854b9234 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -101,7 +101,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; -import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS; @@ -344,6 +344,7 @@ import android.util.FeatureFlagUtils; import android.util.IndentingPrintWriter; import android.util.IntArray; import android.util.Log; +import android.util.LogWriter; import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -484,9 +485,11 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiFunction; @@ -4925,14 +4928,8 @@ public class ActivityManagerService extends IActivityManager.Stub EventLogTags.writeAmProcBound(app.userId, pid, app.processName); synchronized (mProcLock) { - app.mState.setCurAdj(ProcessList.INVALID_ADJ); - app.mState.setSetAdj(ProcessList.INVALID_ADJ); - app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ); - mOomAdjuster.setAttachingSchedGroupLSP(app); - app.mState.setForcingToImportant(null); + mOomAdjuster.setAttachingProcessStatesLSP(app); clearProcessForegroundLocked(app); - app.mState.setHasShownUi(false); - app.mState.setCached(false); app.setDebugging(false); app.setKilledByAm(false); app.setKilled(false); @@ -5100,8 +5097,14 @@ public class ActivityManagerService extends IActivityManager.Stub app.makeActive(thread, mProcessStats); checkTime(startTime, "attachApplicationLocked: immediately after bindApplication"); } + app.setPendingFinishAttach(true); + updateLruProcessLocked(app, false, null); checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked"); + + updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); + checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked"); + final long now = SystemClock.uptimeMillis(); synchronized (mAppProfiler.mProfilerLock) { app.mProfile.setLastRequestedGc(now); @@ -5117,8 +5120,6 @@ public class ActivityManagerService extends IActivityManager.Stub if (!mConstants.mEnableWaitForFinishAttachApplication) { finishAttachApplicationInner(startSeq, callingUid, pid); - } else { - app.setPendingFinishAttach(true); } } catch (Exception e) { // We need kill the process group here. (b/148588589) @@ -5587,8 +5588,11 @@ public class ActivityManagerService extends IActivityManager.Stub boolean isChangeEnabled = CompatChanges.isChangeEnabled( PendingIntent.BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT, owningUid); - logUnsafeMutableImplicitPi(packageName, resolvedTypes, owningUid, i, intent, - isChangeEnabled); + String resolvedType = resolvedTypes == null + || i >= resolvedTypes.length ? null : resolvedTypes[i]; + ActivityManagerUtils.logUnsafeIntentEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED, + owningUid, intent, resolvedType, isChangeEnabled); if (isChangeEnabled) { String msg = packageName + ": Targeting U+ (version " + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows" @@ -5654,24 +5658,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - private void logUnsafeMutableImplicitPi(String packageName, String[] resolvedTypes, - int owningUid, int i, Intent intent, boolean isChangeEnabled) { - String[] categories = intent.getCategories() == null ? new String[0] - : intent.getCategories().toArray(String[]::new); - String resolvedType = resolvedTypes == null || i >= resolvedTypes.length ? null - : resolvedTypes[i]; - FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED, - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED, - owningUid, - null, - packageName, - intent.getAction(), - categories, - resolvedType, - intent.getScheme(), - isChangeEnabled); - } - @Override public int sendIntentSender(IApplicationThread caller, IIntentSender target, IBinder allowlistToken, int code, Intent intent, String resolvedType, @@ -12911,18 +12897,9 @@ public class ActivityManagerService extends IActivityManager.Stub boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid( ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, callingUid); - String[] categories = intent.getCategories() == null ? new String[0] - : intent.getCategories().toArray(String[]::new); - FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED, - FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, - callingUid, - componentInfo, - callerPackage, - intent.getAction(), - categories, - resolvedType, - intent.getScheme(), - hasToBeExportedToMatch); + ActivityManagerUtils.logUnsafeIntentEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, + callingUid, intent, resolvedType, hasToBeExportedToMatch); if (!hasToBeExportedToMatch) { return; } @@ -14505,7 +14482,7 @@ public class ActivityManagerService extends IActivityManager.Stub brOptions.setDeferUntilActive(true); } - if (ordered && brOptions != null && brOptions.isDeferUntilActive()) { + if (mEnableModernQueue && ordered && brOptions != null && brOptions.isDeferUntilActive()) { throw new IllegalArgumentException("Ordered broadcasts can't be deferred until active"); } @@ -18867,10 +18844,11 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void waitForBroadcastBarrier() { - waitForBroadcastBarrier(/* printWriter= */ null, false); + waitForBroadcastBarrier(/* printWriter= */ null, false, false); } - public void waitForBroadcastBarrier(@Nullable PrintWriter pw, boolean flushBroadcastLoopers) { + public void waitForBroadcastBarrier(@Nullable PrintWriter pw, + boolean flushBroadcastLoopers, boolean flushApplicationThreads) { enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()"); if (flushBroadcastLoopers) { BroadcastLoopers.waitForBarrier(pw); @@ -18878,6 +18856,76 @@ public class ActivityManagerService extends IActivityManager.Stub for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForBarrier(pw); } + if (flushApplicationThreads) { + waitForApplicationBarrier(pw); + } + } + + /** + * Wait for all pending {@link IApplicationThread} events to be processed in + * all currently running apps. + */ + public void waitForApplicationBarrier(@Nullable PrintWriter pw) { + if (pw == null) { + pw = new PrintWriter(new LogWriter(Log.VERBOSE, TAG)); + } + + final CountDownLatch finishedLatch = new CountDownLatch(1); + final AtomicInteger pingCount = new AtomicInteger(0); + final AtomicInteger pongCount = new AtomicInteger(0); + final RemoteCallback pongCallback = new RemoteCallback((result) -> { + if (pongCount.incrementAndGet() == pingCount.get()) { + finishedLatch.countDown(); + } + }); + + // Insert an extra "ping" as a sentinel value to guard us from finishing + // too quickly in parallel below + pingCount.incrementAndGet(); + + synchronized (mProcLock) { + final ArrayMap<String, SparseArray<ProcessRecord>> pmap = + mProcessList.getProcessNamesLOSP().getMap(); + final int numProc = pmap.size(); + for (int iProc = 0; iProc < numProc; iProc++) { + final SparseArray<ProcessRecord> apps = pmap.valueAt(iProc); + for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) { + final ProcessRecord app = apps.valueAt(iApp); + final IApplicationThread thread = app.getOnewayThread(); + if (thread != null) { + mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app, + OomAdjuster.OOM_ADJ_REASON_NONE); + pingCount.incrementAndGet(); + try { + thread.schedulePing(pongCallback); + } catch (RemoteException ignored) { + // When we failed to ping remote process, pretend as + // if we received the expected pong + pongCallback.sendResult(null); + } + } + } + } + } + + // Now that we've dispatched all "ping" events above, we can send our + // "pong" sentinel value + pongCallback.sendResult(null); + + // Wait for any remaining "pong" events to trickle in + for (int i = 0; i < 30; i++) { + try { + if (finishedLatch.await(1, TimeUnit.SECONDS)) { + pw.println("Finished application barriers!"); + return; + } else { + pw.println("Waiting for application barriers, at " + pongCount.get() + " of " + + pingCount.get() + "..."); + } + } catch (InterruptedException ignored) { + } + } + pw.println("Gave up waiting for application barriers!"); } void setIgnoreDeliveryGroupPolicy(@NonNull String broadcastAction) { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 4c1835eb80f8..523ed6923b26 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -19,7 +19,7 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; -import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK; +import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM; @@ -359,6 +359,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runWaitForBroadcastIdle(pw); case "wait-for-broadcast-barrier": return runWaitForBroadcastBarrier(pw); + case "wait-for-application-barrier": + return runWaitForApplicationBarrier(pw); case "set-ignore-delivery-group-policy": return runSetIgnoreDeliveryGroupPolicy(pw); case "clear-ignore-delivery-group-policy": @@ -2014,7 +2016,7 @@ final class ActivityManagerShellCommand extends ShellCommand { int mask = PROCESS_CAPABILITY_FOREGROUND_LOCATION | PROCESS_CAPABILITY_FOREGROUND_CAMERA | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE - | PROCESS_CAPABILITY_NETWORK; + | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; while ((opt=getNextOption()) != null) { if (opt.equals("--oom")) { @@ -3332,16 +3334,24 @@ final class ActivityManagerShellCommand extends ShellCommand { int runWaitForBroadcastBarrier(PrintWriter pw) throws RemoteException { boolean flushBroadcastLoopers = false; + boolean flushApplicationThreads = false; String opt; while ((opt = getNextOption()) != null) { if (opt.equals("--flush-broadcast-loopers")) { flushBroadcastLoopers = true; + } else if (opt.equals("--flush-application-threads")) { + flushApplicationThreads = true; } else { getErrPrintWriter().println("Error: Unknown option: " + opt); return -1; } } - mInternal.waitForBroadcastBarrier(pw, flushBroadcastLoopers); + mInternal.waitForBroadcastBarrier(pw, flushBroadcastLoopers, flushApplicationThreads); + return 0; + } + + int runWaitForApplicationBarrier(PrintWriter pw) throws RemoteException { + mInternal.waitForApplicationBarrier(pw); return 0; } diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java index 9be553c49a35..01466b845a61 100644 --- a/services/core/java/com/android/server/am/ActivityManagerUtils.java +++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java @@ -17,11 +17,13 @@ package com.android.server.am; import android.app.ActivityThread; import android.content.ContentResolver; +import android.content.Intent; import android.provider.Settings; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -133,4 +135,25 @@ public class ActivityManagerUtils { public static int hashComponentNameForAtom(String shortInstanceName) { return getUnsignedHashUnCached(shortInstanceName) ^ getAndroidIdHash(); } + + /** + * Helper method to log an unsafe intent event. + */ + public static void logUnsafeIntentEvent(int event, int callingUid, + Intent intent, String resolvedType, boolean blocked) { + String[] categories = intent.getCategories() == null ? new String[0] + : intent.getCategories().toArray(String[]::new); + String component = intent.getComponent() == null ? null + : intent.getComponent().flattenToString(); + FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED, + event, + callingUid, + component, + intent.getPackage(), + intent.getAction(), + categories, + resolvedType, + intent.getScheme(), + blocked); + } } diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 32d20718c192..1ba326680fc2 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -674,7 +674,7 @@ public final class AppExitInfoTracker { break; } } - } catch (IOException | IllegalArgumentException | WireTypeMismatchException e) { + } catch (Exception e) { Slog.w(TAG, "Error in loading historical app exit info from persistent storage: " + e); } finally { if (fin != null) { diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index 050ac194616f..ac2c725ce80d 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -1892,15 +1892,11 @@ public class AppProfiler { } long getCpuTimeForPid(int pid) { - synchronized (mProcessCpuTracker) { - return mProcessCpuTracker.getCpuTimeForPid(pid); - } + return mProcessCpuTracker.getCpuTimeForPid(pid); } long getCpuDelayTimeForPid(int pid) { - synchronized (mProcessCpuTracker) { - return mProcessCpuTracker.getCpuDelayTimeForPid(pid); - } + return mProcessCpuTracker.getCpuDelayTimeForPid(pid); } List<ProcessCpuTracker.Stats> getCpuStats(Predicate<ProcessCpuTracker.Stats> predicate) { diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 160756616907..0ee883f745ca 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.POWER_SAVER; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; @@ -479,9 +480,29 @@ public final class BatteryStatsService extends IBatteryStats.Stub BatteryStatsService.this.noteJobsDeferred(uid, numDeferred, sinceLast); } + private int transportToSubsystem(NetworkCapabilities nc) { + if (nc.hasTransport(TRANSPORT_WIFI)) { + return CPU_WAKEUP_SUBSYSTEM_WIFI; + } + return CPU_WAKEUP_SUBSYSTEM_UNKNOWN; + } + @Override public void noteCpuWakingNetworkPacket(Network network, long elapsedMillis, int uid) { - Slog.d(TAG, "Wakeup due to incoming packet on network " + network + " to uid " + uid); + if (uid < 0) { + Slog.e(TAG, "Invalid uid for waking network packet: " + uid); + return; + } + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + final NetworkCapabilities nc = cm.getNetworkCapabilities(network); + final int subsystem = transportToSubsystem(nc); + + if (subsystem == CPU_WAKEUP_SUBSYSTEM_UNKNOWN) { + Slog.wtf(TAG, "Could not map transport for network: " + network + + " while attributing wakeup by packet sent to uid: " + uid); + return; + } + noteCpuWakingActivity(subsystem, elapsedMillis, uid); } @Override diff --git a/services/core/java/com/android/server/am/BroadcastHistory.java b/services/core/java/com/android/server/am/BroadcastHistory.java index 6ac0e8bee58b..34658ca41356 100644 --- a/services/core/java/com/android/server/am/BroadcastHistory.java +++ b/services/core/java/com/android/server/am/BroadcastHistory.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Intent; import android.os.Bundle; import android.util.TimeUtils; @@ -26,6 +27,7 @@ import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; /** @@ -48,6 +50,11 @@ public class BroadcastHistory { } /** + * List of broadcasts which are being delivered or yet to be delivered. + */ + private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>(); + + /** * Historical data of past broadcasts, for debugging. This is a ring buffer * whose last element is at mHistoryNext. */ @@ -70,7 +77,16 @@ public class BroadcastHistory { final long[] mSummaryHistoryDispatchTime; final long[] mSummaryHistoryFinishTime; - public void addBroadcastToHistoryLocked(BroadcastRecord original) { + void onBroadcastEnqueuedLocked(@NonNull BroadcastRecord r) { + mPendingBroadcasts.add(r); + } + + void onBroadcastFinishedLocked(@NonNull BroadcastRecord r) { + mPendingBroadcasts.remove(r); + addBroadcastToHistoryLocked(r); + } + + public void addBroadcastToHistoryLocked(@NonNull BroadcastRecord original) { // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords, // So don't change the incoming record directly. final BroadcastRecord historyRecord = original.maybeStripForHistory(); @@ -93,7 +109,12 @@ public class BroadcastHistory { } @NeverCompile - public void dumpDebug(ProtoOutputStream proto) { + public void dumpDebug(@NonNull ProtoOutputStream proto) { + for (int i = 0; i < mPendingBroadcasts.size(); ++i) { + final BroadcastRecord r = mPendingBroadcasts.get(i); + r.dumpDebug(proto, BroadcastQueueProto.PENDING_BROADCASTS); + } + int lastIndex = mHistoryNext; int ringIndex = lastIndex; do { @@ -127,8 +148,20 @@ public class BroadcastHistory { } @NeverCompile - public boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName, - SimpleDateFormat sdf, boolean dumpAll, boolean needSep) { + public boolean dumpLocked(@NonNull PrintWriter pw, @Nullable String dumpPackage, + @NonNull String queueName, @NonNull SimpleDateFormat sdf, + boolean dumpAll, boolean needSep) { + pw.println(" Pending broadcasts:"); + if (mPendingBroadcasts.isEmpty()) { + pw.println(" <empty>"); + } else { + for (int idx = mPendingBroadcasts.size() - 1; idx >= 0; --idx) { + final BroadcastRecord r = mPendingBroadcasts.get(idx); + pw.print(" Broadcast #"); pw.print(idx); pw.println(":"); + r.dump(pw, " ", sdf); + } + } + int i; boolean printed = false; diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 84c03e59c658..32e5fd1ef3fd 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -1145,8 +1145,11 @@ class BroadcastProcessQueue { pw.print(" because "); pw.print(reasonToString(mRunnableAtReason)); pw.println(); - pw.print("mProcessCached="); pw.println(mProcessCached); + pw.increaseIndent(); + dumpProcessState(pw); + dumpBroadcastCounts(pw); + if (mActive != null) { dumpRecord("ACTIVE", now, pw, mActive, mActiveIndex); } @@ -1167,6 +1170,49 @@ class BroadcastProcessQueue { } @NeverCompile + private void dumpProcessState(@NonNull IndentingPrintWriter pw) { + final StringBuilder sb = new StringBuilder(); + if (mProcessCached) { + sb.append("CACHED"); + } + if (mProcessInstrumented) { + if (sb.length() > 0) sb.append("|"); + sb.append("INSTR"); + } + if (mProcessPersistent) { + if (sb.length() > 0) sb.append("|"); + sb.append("PER"); + } + if (sb.length() > 0) { + pw.print("state:"); pw.println(sb); + } + if (runningOomAdjusted) { + pw.print("runningOomAdjusted:"); pw.println(runningOomAdjusted); + } + } + + @NeverCompile + private void dumpBroadcastCounts(@NonNull IndentingPrintWriter pw) { + pw.print("e:"); pw.print(mCountEnqueued); + pw.print(" d:"); pw.print(mCountDeferred); + pw.print(" f:"); pw.print(mCountForeground); + pw.print(" fd:"); pw.print(mCountForegroundDeferred); + pw.print(" o:"); pw.print(mCountOrdered); + pw.print(" a:"); pw.print(mCountAlarm); + pw.print(" p:"); pw.print(mCountPrioritized); + pw.print(" pd:"); pw.print(mCountPrioritizedDeferred); + pw.print(" int:"); pw.print(mCountInteractive); + pw.print(" rt:"); pw.print(mCountResultTo); + pw.print(" ins:"); pw.print(mCountInstrumented); + pw.print(" m:"); pw.print(mCountManifest); + + pw.print(" csi:"); pw.print(mActiveCountSinceIdle); + pw.print(" ccu:"); pw.print(mActiveCountConsecutiveUrgent); + pw.print(" ccn:"); pw.print(mActiveCountConsecutiveNormal); + pw.println(); + } + + @NeverCompile private void dumpRecord(@Nullable String flavor, @UptimeMillisLong long now, @NonNull IndentingPrintWriter pw, @NonNull BroadcastRecord record, int recordIndex) { TimeUtils.formatDuration(record.enqueueTime, now, pw); diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 841b61e8e81f..81ca267b9f63 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -90,7 +90,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -602,6 +601,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.enqueueTime = SystemClock.uptimeMillis(); r.enqueueRealTime = SystemClock.elapsedRealtime(); r.enqueueClockTime = System.currentTimeMillis(); + mHistory.onBroadcastEnqueuedLocked(r); ArraySet<BroadcastRecord> replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null); if (replacedBroadcasts == null) { @@ -825,8 +825,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (app != null && app.isInFullBackup()) { return "isInFullBackup"; } - if (mSkipPolicy.shouldSkip(r, receiver)) { - return "mSkipPolicy"; + final String skipReason = mSkipPolicy.shouldSkipMessage(r, receiver); + if (skipReason != null) { + return skipReason; } final Intent receiverIntent = r.getReceiverIntent(receiver); if (receiverIntent == null) { @@ -1100,7 +1101,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { */ private void setDeliveryState(@Nullable BroadcastProcessQueue queue, @Nullable ProcessRecord app, @NonNull BroadcastRecord r, int index, - @NonNull Object receiver, @DeliveryState int newDeliveryState, String reason) { + @NonNull Object receiver, @DeliveryState int newDeliveryState, + @NonNull String reason) { final int cookie = traceBegin("setDeliveryState"); final int oldDeliveryState = getDeliveryState(r, index); boolean checkFinished = false; @@ -1108,7 +1110,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Only apply state when we haven't already reached a terminal state; // this is how we ignore racing timeout messages if (!isDeliveryStateTerminal(oldDeliveryState)) { - r.setDeliveryState(index, newDeliveryState); + r.setDeliveryState(index, newDeliveryState, reason); if (oldDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) { r.deferredCount--; } else if (newDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) { @@ -1659,7 +1661,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { mService.notifyBroadcastFinishedLocked(r); r.finishTime = SystemClock.uptimeMillis(); r.nextReceiver = r.receivers.size(); - mHistory.addBroadcastToHistoryLocked(r); + mHistory.onBroadcastFinishedLocked(r); BroadcastQueueImpl.logBootCompletedBroadcastCompletionLatencyIfPossible(r); @@ -1833,8 +1835,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (dumpConstants) { mConstants.dump(ipw); } + if (dumpHistory) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); needSep = mHistory.dumpLocked(ipw, dumpPackage, mQueueName, sdf, dumpAll, needSep); } return needSep; diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index f793c5078b5e..59f33ddb795d 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -99,6 +99,7 @@ final class BroadcastRecord extends Binder { final @Nullable BroadcastOptions options; // BroadcastOptions supplied by caller final @NonNull List<Object> receivers; // contains BroadcastFilter and ResolveInfo final @DeliveryState int[] delivery; // delivery state of each receiver + final @NonNull String[] deliveryReasons; // reasons for delivery state of each receiver final boolean[] deferredUntilActive; // whether each receiver is infinitely deferred final int[] blockedUntilTerminalCount; // blocked until count of each receiver @Nullable ProcessRecord resultToApp; // who receives final result if non-null @@ -298,7 +299,7 @@ final class BroadcastRecord extends Binder { pw.print(" initialSticky="); pw.println(initialSticky); } if (nextReceiver != 0) { - pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver); + pw.print(prefix); pw.print("nextReceiver="); pw.println(nextReceiver); } if (curFilter != null) { pw.print(prefix); pw.print("curFilter="); pw.println(curFilter); @@ -328,6 +329,7 @@ final class BroadcastRecord extends Binder { } pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr); } + pw.print(prefix); pw.print("terminalCount="); pw.println(terminalCount); final int N = receivers != null ? receivers.size() : 0; String p2 = prefix + " "; PrintWriterPrinter printer = new PrintWriterPrinter(pw); @@ -346,6 +348,7 @@ final class BroadcastRecord extends Binder { TimeUtils.formatDuration(terminalTime[i] - scheduledTime[i], pw); pw.print(' '); } + pw.print("("); pw.print(blockedUntilTerminalCount[i]); pw.print(") "); pw.print("#"); pw.print(i); pw.print(": "); if (o instanceof BroadcastFilter) { pw.println(o); @@ -356,6 +359,9 @@ final class BroadcastRecord extends Binder { } else { pw.println(o); } + if (deliveryReasons[i] != null) { + pw.print(p2); pw.print("reason: "); pw.println(deliveryReasons[i]); + } } } @@ -393,6 +399,7 @@ final class BroadcastRecord extends Binder { options = _options; receivers = (_receivers != null) ? _receivers : EMPTY_RECEIVERS; delivery = new int[_receivers != null ? _receivers.size() : 0]; + deliveryReasons = new String[delivery.length]; deferUntilActive = options != null ? options.isDeferUntilActive() : false; deferredUntilActive = new boolean[deferUntilActive ? delivery.length : 0]; blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized); @@ -448,6 +455,7 @@ final class BroadcastRecord extends Binder { options = from.options; receivers = from.receivers; delivery = from.delivery; + deliveryReasons = from.deliveryReasons; deferUntilActive = from.deferUntilActive; deferredUntilActive = from.deferredUntilActive; blockedUntilTerminalCount = from.blockedUntilTerminalCount; @@ -609,8 +617,10 @@ final class BroadcastRecord extends Binder { * Update the delivery state of the given {@link #receivers} index. * Automatically updates any time measurements related to state changes. */ - void setDeliveryState(int index, @DeliveryState int deliveryState) { + void setDeliveryState(int index, @DeliveryState int deliveryState, + @NonNull String reason) { delivery[index] = deliveryState; + deliveryReasons[index] = reason; if (deferUntilActive) deferredUntilActive[index] = false; switch (deliveryState) { case DELIVERY_DELIVERED: @@ -977,7 +987,8 @@ final class BroadcastRecord extends Binder { if (label == null) { label = intent.toString(); } - mCachedToShortString = label + "/u" + userId; + mCachedToShortString = Integer.toHexString(System.identityHashCode(this)) + + ":" + label + "/u" + userId; } return mCachedToShortString; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 679cf0a5694b..712142185863 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -22,8 +22,8 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; -import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; +import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; @@ -117,6 +117,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.ServiceInfo; +import android.net.NetworkPolicyManager; import android.os.Handler; import android.os.IBinder; import android.os.PowerManagerInternal; @@ -1259,12 +1260,19 @@ public class OomAdjuster { for (int i = numLru - 1; i >= 0; i--) { ProcessRecord app = lruList.get(i); final ProcessStateRecord state = app.mState; - if (!app.isKilledByAm() && app.getThread() != null && !app.isPendingFinishAttach()) { + if (!app.isKilledByAm() && app.getThread() != null) { // We don't need to apply the update for the process which didn't get computed if (state.getCompletedAdjSeq() == mAdjSeq) { applyOomAdjLSP(app, true, now, nowElapsed, oomAdjReason); } + if (app.isPendingFinishAttach()) { + // Avoid trimming processes that are still initializing. If they aren't + // hosting any components yet because they may be unfairly killed. + // We however apply any computed previously computed oom scores before skipping. + continue; + } + final ProcessServiceRecord psr = app.mServices; // Count the number of process types. switch (state.getCurProcState()) { @@ -1698,6 +1706,19 @@ public class OomAdjuster { return false; } + if (app.isPendingFinishAttach()) { + state.setAdjSeq(mAdjSeq); + state.setCompletedAdjSeq(mAdjSeq); + // If the process is still initializing, we skip computing any states because we + // don't want to override the special states that have been set at + // AMS#attachApplication with OomAdjuster#setAttachingProcessStates. + // In this limbo state, the app has |PROC_START_TIMEOUT| to finish attach application + // and receive updated proc_state based on its importance. + // Note that in this state, the oom_score is INVALID_ADJ which is outside the standard + // oom score range and the app is safe from lmkd kills. + return false; + } + state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN); state.setAdjSource(null); state.setAdjTarget(null); @@ -2260,14 +2281,15 @@ public class OomAdjuster { // elevated to a high enough procstate anyway to get network unless they // request otherwise, so don't propagate the network capability by default // in this case unless they explicitly request it. - if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) { + if ((cstate.getCurCapability() + & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) { if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { // This is used to grant network access to Expedited Jobs. if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) { - capability |= PROCESS_CAPABILITY_NETWORK; + capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; } } else { - capability |= PROCESS_CAPABILITY_NETWORK; + capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; } } @@ -2778,27 +2800,33 @@ public class OomAdjuster { } private int getDefaultCapability(ProcessRecord app, int procState) { + final int networkCapabilities = + NetworkPolicyManager.getDefaultProcessNetworkCapabilities(procState); + final int baseCapabilities; switch (procState) { case PROCESS_STATE_PERSISTENT: case PROCESS_STATE_PERSISTENT_UI: case PROCESS_STATE_TOP: - return PROCESS_CAPABILITY_ALL; // BFSL allowed + baseCapabilities = PROCESS_CAPABILITY_ALL; // BFSL allowed + break; case PROCESS_STATE_BOUND_TOP: - return PROCESS_CAPABILITY_NETWORK | PROCESS_CAPABILITY_BFSL; + baseCapabilities = PROCESS_CAPABILITY_BFSL; + break; case PROCESS_STATE_FOREGROUND_SERVICE: if (app.getActiveInstrumentation() != null) { - return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK ; + baseCapabilities = PROCESS_CAPABILITY_ALL_IMPLICIT; } else { // Capability from foreground service is conditional depending on // foregroundServiceType in the manifest file and the // mAllowWhileInUsePermissionInFgs flag. - return PROCESS_CAPABILITY_NETWORK; + baseCapabilities = PROCESS_CAPABILITY_NONE; } - case PROCESS_STATE_BOUND_FOREGROUND_SERVICE: - return PROCESS_CAPABILITY_NETWORK; + break; default: - return PROCESS_CAPABILITY_NONE; + baseCapabilities = PROCESS_CAPABILITY_NONE; + break; } + return baseCapabilities | networkCapabilities; } /** @@ -3211,7 +3239,7 @@ public class OomAdjuster { } @GuardedBy({"mService", "mProcLock"}) - void setAttachingSchedGroupLSP(ProcessRecord app) { + void setAttachingProcessStatesLSP(ProcessRecord app) { int initialSchedGroup = SCHED_GROUP_DEFAULT; final ProcessStateRecord state = app.mState; // If the process has been marked as foreground, it is starting as the top app (with @@ -3231,6 +3259,15 @@ public class OomAdjuster { state.setSetSchedGroup(initialSchedGroup); state.setCurrentSchedulingGroup(initialSchedGroup); + state.setCurProcState(PROCESS_STATE_CACHED_EMPTY); + state.setCurCapability(PROCESS_CAPABILITY_NONE); + + state.setCurAdj(ProcessList.FOREGROUND_APP_ADJ); + state.setSetAdj(ProcessList.FOREGROUND_APP_ADJ); + state.setVerifiedAdj(ProcessList.FOREGROUND_APP_ADJ); + state.setForcingToImportant(null); + state.setHasShownUi(false); + state.setCached(true); } // ONLY used for unit testing in OomAdjusterTests.java diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index f4e2b0f38f13..35f71f74d0e1 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -3100,9 +3100,10 @@ public final class ProcessList { hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName()); final ProcessStateRecord state = r.mState; - if (!mService.mBooted && !mService.mBooting + if (!isolated && !isSdkSandbox && userId == UserHandle.USER_SYSTEM - && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { + && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK + && (TextUtils.equals(proc, info.processName))) { // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc. state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT); diff --git a/services/core/java/com/android/server/am/SameProcessApplicationThread.java b/services/core/java/com/android/server/am/SameProcessApplicationThread.java index 82dd5c2cf2c3..6deaf7b7fe4f 100644 --- a/services/core/java/com/android/server/am/SameProcessApplicationThread.java +++ b/services/core/java/com/android/server/am/SameProcessApplicationThread.java @@ -25,6 +25,7 @@ import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo; import android.os.Bundle; import android.os.Handler; +import android.os.RemoteCallback; import android.os.RemoteException; import java.util.List; @@ -77,17 +78,23 @@ public class SameProcessApplicationThread extends IApplicationThread.Default { @Override public void scheduleReceiverList(List<ReceiverInfo> info) { - for (int i = 0; i < info.size(); i++) { - ReceiverInfo r = info.get(i); - if (r.registered) { - scheduleRegisteredReceiver(r.receiver, r.intent, - r.resultCode, r.data, r.extras, r.ordered, r.sticky, r.assumeDelivered, - r.sendingUser, r.processState, r.sendingUid, r.sendingPackage); - } else { - scheduleReceiver(r.intent, r.activityInfo, r.compatInfo, - r.resultCode, r.data, r.extras, r.sync, r.assumeDelivered, - r.sendingUser, r.processState, r.sendingUid, r.sendingPackage); + mHandler.post(() -> { + try { + mWrapped.scheduleReceiverList(info); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + }); + } + + @Override + public void schedulePing(RemoteCallback pong) { + mHandler.post(() -> { + try { + mWrapped.schedulePing(pong); + } catch (RemoteException e) { + throw new RuntimeException(e); } - } + }); } } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index ae8ceab62896..61801177ffba 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -468,6 +468,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN long fgToken = proto.start(ServiceRecordProto.FOREGROUND); proto.write(ServiceRecordProto.Foreground.ID, foregroundId); foregroundNoti.dumpDebug(proto, ServiceRecordProto.Foreground.NOTIFICATION); + proto.write(ServiceRecordProto.Foreground.FOREGROUND_SERVICE_TYPE, + foregroundServiceType); proto.end(fgToken); } ProtoUtils.toDuration(proto, ServiceRecordProto.CREATE_REAL_TIME, createRealTime, nowReal); diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java index 49279d44ea7c..bb8d3f4c2d7d 100644 --- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java +++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java @@ -213,8 +213,6 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { @Override public void updateUidProcState(int uid, int procState, int capability) { - mEventLog.logUpdateUidProcState(uid, procState, capability); - int uidState = processStateToUidState(procState); int prevUidState = mUidStates.get(uid, AppOpsManager.MIN_PRIORITY_UID_STATE); @@ -226,6 +224,10 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { && (uidState != prevUidState || capability != prevCapability)) || (pendingStateCommitTime != 0 && (uidState != pendingUidState || capability != pendingCapability))) { + + // If this process update results in a capability or uid state change, log it. It's + // not interesting otherwise. + mEventLog.logUpdateUidProcState(uid, procState, capability); mPendingUidStates.put(uid, uidState); mPendingCapability.put(uid, capability); @@ -327,9 +329,12 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { } private void commitUidPendingState(int uid) { - int pendingUidState = mPendingUidStates.get(uid, MIN_PRIORITY_UID_STATE); - int pendingCapability = mPendingCapability.get(uid, PROCESS_CAPABILITY_NONE); - boolean pendingVisibleAppWidget = mPendingVisibleAppWidget.get(uid, false); + int pendingUidState = mPendingUidStates.get(uid, + mUidStates.get(uid, MIN_PRIORITY_UID_STATE)); + int pendingCapability = mPendingCapability.get(uid, + mCapability.get(uid, PROCESS_CAPABILITY_NONE)); + boolean pendingVisibleAppWidget = mPendingVisibleAppWidget.get(uid, + mVisibleAppWidget.get(uid, false)); int uidState = mUidStates.get(uid, MIN_PRIORITY_UID_STATE); int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE); @@ -386,10 +391,8 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { private static class EventLog { - // These seems a bit too verbose and not as useful, turning off for now. - // DCE should be able to remove most associated code. // Memory usage: 16 * size bytes - private static final int UPDATE_UID_PROC_STATE_LOG_MAX_SIZE = 0; + private static final int UPDATE_UID_PROC_STATE_LOG_MAX_SIZE = 200; // Memory usage: 20 * size bytes private static final int COMMIT_UID_STATE_LOG_MAX_SIZE = 200; // Memory usage: 24 * size bytes diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING index 300a2c84888d..2cea32af2396 100644 --- a/services/core/java/com/android/server/audio/TEST_MAPPING +++ b/services/core/java/com/android/server/audio/TEST_MAPPING @@ -1,5 +1,5 @@ { - "presubmit-large": [ + "presubmit": [ { "name": "CtsMediaAudioTestCases", "options": [ @@ -24,9 +24,7 @@ "include-annotation": "android.platform.test.annotations.Presubmit" } ] - } - ], - "presubmit": [ + }, { "name": "FrameworksServicesTests", "options": [ diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java index 42be95b7377a..ecb7e7ca08fb 100644 --- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java +++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java @@ -20,8 +20,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; import android.hardware.biometrics.IBiometricContextListener; +import android.hardware.biometrics.common.AuthenticateReason; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.common.OperationReason; +import android.hardware.biometrics.common.WakeReason; +import android.hardware.face.FaceAuthenticateOptions; +import android.hardware.fingerprint.FingerprintAuthenticateOptions; +import android.os.PowerManager; import android.view.Surface; /** @@ -50,12 +55,127 @@ public class OperationContextExt { mAidlContext = context; } - /** Gets the subset of the context that can be shared with the HAL. */ + /** + * Gets the subset of the context that can be shared with the HAL. + * + * When starting a new operation use methods like to update & fetch the context: + * <ul> + * <li>{@link #toAidlContext(FaceAuthenticateOptions)} + * <li>{@link #toAidlContext(FingerprintAuthenticateOptions)} + * </ul> + * + * Use this method for any subsequent calls to the HAL or for operations that do + * not accept any options. + * + * @return the underlying AIDL context + */ @NonNull public OperationContext toAidlContext() { return mAidlContext; } + /** + * Gets the subset of the context that can be shared with the HAL and updates + * it with the given options. + * + * @param options authenticate options + * @return the underlying AIDL context + */ + @NonNull + public OperationContext toAidlContext(@NonNull FaceAuthenticateOptions options) { + mAidlContext.authenticateReason = AuthenticateReason + .faceAuthenticateReason(getAuthReason(options)); + mAidlContext.wakeReason = getWakeReason(options); + + return mAidlContext; + } + + /** + * Gets the subset of the context that can be shared with the HAL and updates + * it with the given options. + * + * @param options authenticate options + * @return the underlying AIDL context + */ + @NonNull + public OperationContext toAidlContext(@NonNull FingerprintAuthenticateOptions options) { + mAidlContext.authenticateReason = AuthenticateReason + .fingerprintAuthenticateReason(getAuthReason(options)); + mAidlContext.wakeReason = getWakeReason(options); + + return mAidlContext; + } + + @AuthenticateReason.Face + private int getAuthReason(@NonNull FaceAuthenticateOptions options) { + switch (options.getAuthenticateReason()) { + case FaceAuthenticateOptions.AUTHENTICATE_REASON_STARTED_WAKING_UP: + return AuthenticateReason.Face.STARTED_WAKING_UP; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN: + return AuthenticateReason.Face.PRIMARY_BOUNCER_SHOWN; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_ASSISTANT_VISIBLE: + return AuthenticateReason.Face.ASSISTANT_VISIBLE; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN: + return AuthenticateReason.Face.ALTERNATE_BIOMETRIC_BOUNCER_SHOWN; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED: + return AuthenticateReason.Face.NOTIFICATION_PANEL_CLICKED; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED: + return AuthenticateReason.Face.OCCLUDING_APP_REQUESTED; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED: + return AuthenticateReason.Face.PICK_UP_GESTURE_TRIGGERED; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_QS_EXPANDED: + return AuthenticateReason.Face.QS_EXPANDED; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER: + return AuthenticateReason.Face.SWIPE_UP_ON_BOUNCER; + case FaceAuthenticateOptions.AUTHENTICATE_REASON_UDFPS_POINTER_DOWN: + return AuthenticateReason.Face.UDFPS_POINTER_DOWN; + default: + return AuthenticateReason.Face.UNKNOWN; + } + } + + @WakeReason + private int getWakeReason(@NonNull FaceAuthenticateOptions options) { + switch (options.getWakeReason()) { + case PowerManager.WAKE_REASON_POWER_BUTTON: + return WakeReason.POWER_BUTTON; + case PowerManager.WAKE_REASON_GESTURE: + return WakeReason.GESTURE; + case PowerManager.WAKE_REASON_WAKE_KEY: + return WakeReason.WAKE_KEY; + case PowerManager.WAKE_REASON_WAKE_MOTION: + return WakeReason.WAKE_MOTION; + case PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED: + return WakeReason.DISPLAY_GROUP_ADDED; + case PowerManager.WAKE_REASON_TAP: + return WakeReason.TAP; + case PowerManager.WAKE_REASON_LIFT: + return WakeReason.LIFT; + case PowerManager.WAKE_REASON_BIOMETRIC: + return WakeReason.BIOMETRIC; + case PowerManager.WAKE_REASON_CAMERA_LAUNCH: + case PowerManager.WAKE_REASON_HDMI: + case PowerManager.WAKE_REASON_DISPLAY_GROUP_TURNED_ON: + case PowerManager.WAKE_REASON_UNFOLD_DEVICE: + case PowerManager.WAKE_REASON_DREAM_FINISHED: + case PowerManager.WAKE_REASON_TILT: + case PowerManager.WAKE_REASON_APPLICATION: + case PowerManager.WAKE_REASON_PLUGGED_IN: + default: + return WakeReason.UNKNOWN; + } + } + + @AuthenticateReason.Fingerprint + private int getAuthReason(@NonNull FingerprintAuthenticateOptions options) { + return AuthenticateReason.Fingerprint.UNKNOWN; + } + + @WakeReason + private int getWakeReason(@NonNull FingerprintAuthenticateOptions options) { + return WakeReason.UNKNOWN; + } + /** {@link OperationContext#id}. */ public int getId() { return mAidlContext.id; diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 005ad20a2d48..7b9fc36e8d61 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -74,6 +74,7 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions> @Nullable private final TaskStackListener mTaskStackListener; private final LockoutTracker mLockoutTracker; + private final O mOptions; private final boolean mIsRestricted; private final boolean mAllowBackgroundAuthentication; // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update @@ -110,6 +111,7 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions> mAllowBackgroundAuthentication = allowBackgroundAuthentication; mShouldUseLockoutTracker = lockoutTracker != null; mSensorStrength = sensorStrength; + mOptions = options; } @LockoutTracker.LockoutMode @@ -151,6 +153,11 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions> return Utils.isSettings(getContext(), getOwnerString()); } + /** The options requested at the start of the operation. */ + protected O getOptions() { + return mOptions; + } + @Override protected boolean isCryptoOperation() { return mOperationId != 0; diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java index 7b8f82441fd6..f516a4930a58 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java @@ -37,6 +37,7 @@ public class BiometricNotificationUtils { private static final String TAG = "BiometricNotificationUtils"; private static final String RE_ENROLL_NOTIFICATION_TAG = "FaceService"; private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintService"; + private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock"; private static final int NOTIFICATION_ID = 1; private static final long NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000; private static long sLastAlertTime = 0; @@ -57,6 +58,7 @@ public class BiometricNotificationUtils { final Intent intent = new Intent("android.settings.FACE_SETTINGS"); intent.setPackage("com.android.settings"); + intent.putExtra(KEY_RE_ENROLL_FACE, true); final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */, diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index 6d7b2cb40e21..c2994a953f31 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -260,9 +260,8 @@ public class FaceService extends SystemService { if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); return -1; - } else { - options.setSensorId(provider.first); } + options.setSensorId(provider.first); return provider.second.scheduleAuthenticate(token, operationId, 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options, @@ -286,6 +285,7 @@ public class FaceService extends SystemService { Slog.w(TAG, "Null provider for detectFace"); return -1; } + options.setSensorId(provider.first); return provider.second.scheduleFaceDetect(token, new ClientMonitorCallbackConverter(receiver), options, diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index 976f1cbe1e5c..84e2fb4a5966 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -166,7 +166,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession, FaceAut if (session.hasContextMethods()) { return session.getSession().authenticateWithContext( - mOperationId, getOperationContext().toAidlContext()); + mOperationId, getOperationContext().toAidlContext(getOptions())); } else { return session.getSession().authenticate(mOperationId); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java index e65202dca5cd..fa23ccd482fb 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java @@ -47,6 +47,7 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements private static final String TAG = "FaceDetectClient"; private final boolean mIsStrongBiometric; + private final FaceAuthenticateOptions mOptions; @Nullable private ICancellationSignal mCancellationSignal; @Nullable private SensorPrivacyManager mSensorPrivacyManager; @@ -74,6 +75,7 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements setRequestId(requestId); mIsStrongBiometric = isStrongBiometric; mSensorPrivacyManager = sensorPrivacyManager; + mOptions = options; } @Override @@ -118,7 +120,7 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements if (session.hasContextMethods()) { return session.getSession().detectInteractionWithContext( - getOperationContext().toAidlContext()); + getOperationContext().toAidlContext(mOptions)); } else { return session.getSession().detectInteraction(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index f6c1375730bb..dc00ffc9f922 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -261,7 +261,6 @@ public class FingerprintService extends SystemService { final String opPackageName = options.getOpPackageName(); final String attributionTag = options.getAttributionTag(); final int userId = options.getUserId(); - final int sensorId = options.getSensorId(); if (!canUseFingerprint( opPackageName, @@ -298,21 +297,22 @@ public class FingerprintService extends SystemService { : BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER; final Pair<Integer, ServiceProvider> provider; - if (sensorId == FingerprintManager.SENSOR_ID_ANY) { + if (options.getSensorId() == FingerprintManager.SENSOR_ID_ANY) { provider = mRegistry.getSingleProvider(); } else { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - provider = new Pair<>(sensorId, mRegistry.getProviderForSensor(sensorId)); + provider = new Pair<>(options.getSensorId(), + mRegistry.getProviderForSensor(options.getSensorId())); } + if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); return -1; - } else { - options.setSensorId(provider.first); } + options.setSensorId(provider.first); final FingerprintSensorPropertiesInternal sensorProps = - provider.second.getSensorProperties(sensorId); + provider.second.getSensorProperties(options.getSensorId()); if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName) && sensorProps != null && sensorProps.isAnyUdfpsType()) { try { @@ -431,9 +431,8 @@ public class FingerprintService extends SystemService { if (provider == null) { Slog.w(TAG, "Null provider for detectFingerprint"); return -1; - } else { - options.setSensorId(provider.first); } + options.setSensorId(provider.first); return provider.second.scheduleFingerDetect(token, new ClientMonitorCallbackConverter(receiver), options, diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java index 1630be77ee7b..bae84bd01e05 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java @@ -48,6 +48,8 @@ final class AidlConversionUtils { return BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR; } else if (aidlError == Error.BAD_CALIBRATION) { return BiometricFingerprintConstants.FINGERPRINT_ERROR_BAD_CALIBRATION; + } else if (aidlError == Error.POWER_PRESS) { + return BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED; } else { return BiometricFingerprintConstants.FINGERPRINT_ERROR_UNKNOWN; } @@ -84,6 +86,8 @@ final class AidlConversionUtils { } else if (aidlAcquiredInfo == AcquiredInfo.RETRYING_CAPTURE) { // No framework constant available return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN; + } else if (aidlAcquiredInfo == AcquiredInfo.POWER_PRESS) { + return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED; } else { return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 0f81f9f2660e..435e81d688bd 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -285,7 +285,7 @@ class FingerprintAuthenticationClient if (session.hasContextMethods()) { return session.getSession().authenticateWithContext( - mOperationId, opContext.toAidlContext()); + mOperationId, opContext.toAidlContext(getOptions())); } else { return session.getSession().authenticate(mOperationId); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index 376d23187fb8..16d16fc95c5b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -48,6 +48,7 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements private static final String TAG = "FingerprintDetectClient"; private final boolean mIsStrongBiometric; + private final FingerprintAuthenticateOptions mOptions; @NonNull private final SensorOverlays mSensorOverlays; @Nullable private ICancellationSignal mCancellationSignal; @@ -66,6 +67,7 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements mIsStrongBiometric = isStrongBiometric; mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController*/, udfpsOverlay); + mOptions = options; } @Override @@ -105,7 +107,7 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements if (session.hasContextMethods()) { return session.getSession().detectInteractionWithContext( - getOperationContext().toAidlContext()); + getOperationContext().toAidlContext(mOptions)); } else { return session.getSession().detectInteraction(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index 513b3e3e6e86..c2ca78e91fe3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -274,8 +274,5 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps } @Override - public void onPowerPressed() { - onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED, - 0 /* vendorCode */); - } + public void onPowerPressed() {} } diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java index ce29013f1623..63218ee4e12d 100644 --- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java +++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java @@ -138,6 +138,8 @@ class DeviceStateToLayoutMap { display.setPosition(POSITION_UNKNOWN); } display.setRefreshRateZoneId(d.getRefreshRateZoneId()); + display.setRefreshRateThermalThrottlingMapId( + d.getRefreshRateThermalThrottlingMapId()); } } } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 7b560cecbf21..d57dc471694e 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -22,6 +22,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayViewport; import android.os.IBinder; +import android.util.Slog; import android.view.Display; import android.view.DisplayAddress; import android.view.Surface; @@ -39,6 +40,7 @@ import java.io.PrintWriter; * </p> */ abstract class DisplayDevice { + private static final String TAG = "DisplayDevice"; private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build(); private final DisplayAdapter mDisplayAdapter; @@ -269,10 +271,13 @@ abstract class DisplayDevice { /** * Sets the display layer stack while in a transaction. */ - public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) { + public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, + int layerStackTag) { if (mCurrentLayerStack != layerStack) { mCurrentLayerStack = layerStack; t.setDisplayLayerStack(mDisplayToken, layerStack); + Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for " + + mUniqueId); } } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 75f8accde3a5..cdab77def83e 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -31,6 +31,7 @@ import android.text.TextUtils; import android.util.MathUtils; import android.util.Pair; import android.util.Slog; +import android.util.SparseArray; import android.util.Spline; import android.view.DisplayAddress; import android.view.SurfaceControl; @@ -54,6 +55,8 @@ import com.android.server.display.config.NitsMap; import com.android.server.display.config.Point; import com.android.server.display.config.RefreshRateConfigs; import com.android.server.display.config.RefreshRateRange; +import com.android.server.display.config.RefreshRateThrottlingMap; +import com.android.server.display.config.RefreshRateThrottlingPoint; import com.android.server.display.config.RefreshRateZone; import com.android.server.display.config.SdrHdrRatioMap; import com.android.server.display.config.SdrHdrRatioPoint; @@ -88,6 +91,7 @@ import javax.xml.datatype.DatatypeConfigurationException; * <pre> * {@code * <displayConfiguration> + * <name>Built-In Display</name> * <densityMapping> * <density> * <height>480</height> @@ -149,9 +153,26 @@ import javax.xml.datatype.DatatypeConfigurationException; * <brightness>0.005</brightness> * </brightnessThrottlingPoint> * </concurrentDisplaysBrightnessThrottlingMap> + * <refreshRateThrottlingMap> + * <refreshRateThrottlingPoint> + * <thermalStatus>critical</thermalStatus> + * <refreshRateRange> + * <minimum>0</minimum> + * <maximum>60</maximum> + * </refreshRateRange> + * </refreshRateThrottlingPoint> + * </refreshRateThrottlingMap> * </thermalThrottling> * * <refreshRate> + * <refreshRateZoneProfiles> + * <refreshRateZoneProfile id="concurrent"> + * <refreshRateRange> + * <minimum>60</minimum> + * <maximum>60</maximum> + * </refreshRateRange> + * </refreshRateZoneProfile> + * </refreshRateZoneProfiles> * <defaultRefreshRateInHbmHdr>75</defaultRefreshRateInHbmHdr> * <defaultRefreshRateInHbmSunlight>75</defaultRefreshRateInHbmSunlight> * <lowerBlockingZoneConfigs> @@ -417,7 +438,7 @@ public class DisplayDeviceConfig { public static final String QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC = "canSetBrightnessViaHwc"; - static final String DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID = "default"; + static final String DEFAULT_ID = "default"; private static final float BRIGHTNESS_DEFAULT = 0.5f; private static final String ETC_DIR = "etc"; @@ -479,6 +500,10 @@ public class DisplayDeviceConfig { private final List<RefreshRateLimitation> mRefreshRateLimitations = new ArrayList<>(2 /*initialCapacity*/); + // Name of the display, if configured. + @Nullable + private String mName; + // Nits and backlight values that are loaded from either the display device config file, or // config.xml. These are the raw values and just used for the dumpsys private float[] mRawNits; @@ -662,7 +687,11 @@ public class DisplayDeviceConfig { private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; - private Map<String, BrightnessThrottlingData> mBrightnessThrottlingDataMap = new HashMap(); + private final Map<String, BrightnessThrottlingData> mBrightnessThrottlingDataMap = + new HashMap<>(); + + private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>> + mRefreshRateThrottlingMap = new HashMap<>(); @Nullable private HostUsiVersion mHostUsiVersion; @@ -808,6 +837,15 @@ public class DisplayDeviceConfig { return config; } + /** The name of the display. + * + * @return The name of the display. + */ + @Nullable + public String getName() { + return mName; + } + /** * Return the brightness mapping nits array. * @@ -1315,6 +1353,17 @@ public class DisplayDeviceConfig { } /** + * @param id - throttling data id or null for default + * @return refresh rate throttling configuration + */ + @Nullable + public SparseArray<SurfaceControl.RefreshRateRange> getRefreshRateThrottlingData( + @Nullable String id) { + String key = id == null ? DEFAULT_ID : id; + return mRefreshRateThrottlingMap.get(key); + } + + /** * @return Auto brightness darkening light debounce */ public long getAutoBrightnessDarkeningLightDebounce() { @@ -1552,6 +1601,8 @@ public class DisplayDeviceConfig { + ", mRefreshRateZoneProfiles= " + mRefreshRateZoneProfiles + ", mDefaultRefreshRateInHbmHdr= " + mDefaultRefreshRateInHbmHdr + ", mDefaultRefreshRateInHbmSunlight= " + mDefaultRefreshRateInHbmSunlight + + ", mRefreshRateThrottlingMap= " + mRefreshRateThrottlingMap + + "\n" + ", mLowDisplayBrightnessThresholds= " + Arrays.toString(mLowDisplayBrightnessThresholds) + ", mLowAmbientBrightnessThresholds= " @@ -1609,11 +1660,12 @@ public class DisplayDeviceConfig { try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) { final DisplayConfiguration config = XmlParser.read(in); if (config != null) { + loadName(config); loadDensityMapping(config); loadBrightnessDefaultFromDdcXml(config); loadBrightnessConstraintsFromConfigXml(); loadBrightnessMap(config); - loadBrightnessThrottlingMaps(config); + loadThermalThrottlingConfig(config); loadHighBrightnessModeData(config); loadQuirks(config); loadBrightnessRamps(config); @@ -1680,6 +1732,10 @@ public class DisplayDeviceConfig { } } + private void loadName(DisplayConfiguration config) { + mName = config.getName(); + } + private void loadDensityMapping(DisplayConfiguration config) { if (config.getDensityMapping() == null) { return; @@ -1823,13 +1879,17 @@ public class DisplayDeviceConfig { return Spline.createSpline(nits, ratios); } - private void loadBrightnessThrottlingMaps(DisplayConfiguration config) { + private void loadThermalThrottlingConfig(DisplayConfiguration config) { final ThermalThrottling throttlingConfig = config.getThermalThrottling(); if (throttlingConfig == null) { Slog.i(TAG, "No thermal throttling config found"); return; } + loadBrightnessThrottlingMaps(throttlingConfig); + loadRefreshRateThermalThrottlingMap(throttlingConfig); + } + private void loadBrightnessThrottlingMaps(ThermalThrottling throttlingConfig) { final List<BrightnessThrottlingMap> maps = throttlingConfig.getBrightnessThrottlingMap(); if (maps == null || maps.isEmpty()) { Slog.i(TAG, "No brightness throttling map found"); @@ -1855,7 +1915,7 @@ public class DisplayDeviceConfig { } if (!badConfig) { - String id = map.getId() == null ? DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID + String id = map.getId() == null ? DEFAULT_ID : map.getId(); if (mBrightnessThrottlingDataMap.containsKey(id)) { throw new RuntimeException("Brightness throttling data with ID " + id @@ -1867,6 +1927,57 @@ public class DisplayDeviceConfig { } } + private void loadRefreshRateThermalThrottlingMap(ThermalThrottling throttlingConfig) { + List<RefreshRateThrottlingMap> maps = throttlingConfig.getRefreshRateThrottlingMap(); + if (maps == null || maps.isEmpty()) { + Slog.w(TAG, "RefreshRateThrottling: map not found"); + return; + } + + for (RefreshRateThrottlingMap map : maps) { + List<RefreshRateThrottlingPoint> points = map.getRefreshRateThrottlingPoint(); + String id = map.getId() == null ? DEFAULT_ID : map.getId(); + + if (points == null || points.isEmpty()) { + // Expected at lease 1 throttling point for each map + Slog.w(TAG, "RefreshRateThrottling: points not found for mapId=" + id); + continue; + } + if (mRefreshRateThrottlingMap.containsKey(id)) { + Slog.wtf(TAG, "RefreshRateThrottling: map already exists, mapId=" + id); + continue; + } + + SparseArray<SurfaceControl.RefreshRateRange> refreshRates = new SparseArray<>(); + for (RefreshRateThrottlingPoint point : points) { + ThermalStatus status = point.getThermalStatus(); + if (!thermalStatusIsValid(status)) { + Slog.wtf(TAG, + "RefreshRateThrottling: Invalid thermalStatus=" + status.getRawName() + + ",mapId=" + id); + continue; + } + int thermalStatusInt = convertThermalStatus(status); + if (refreshRates.contains(thermalStatusInt)) { + Slog.wtf(TAG, "RefreshRateThrottling: thermalStatus=" + status.getRawName() + + " is already in the map, mapId=" + id); + continue; + } + + refreshRates.put(thermalStatusInt, new SurfaceControl.RefreshRateRange( + point.getRefreshRateRange().getMinimum().floatValue(), + point.getRefreshRateRange().getMaximum().floatValue() + )); + } + if (refreshRates.size() == 0) { + Slog.w(TAG, "RefreshRateThrottling: no valid throttling points fond for map, mapId=" + + id); + continue; + } + mRefreshRateThrottlingMap.put(id, refreshRates); + } + } + private void loadRefreshRateSetting(DisplayConfiguration config) { final RefreshRateConfigs refreshRateConfigs = (config == null) ? null : config.getRefreshRate(); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 21cc172f5908..55d2921b2878 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2126,16 +2126,24 @@ public final class DisplayManagerService extends SystemService { autoHdrOutputTypes = getEnabledAutoHdrTypesLocked(); } + int conversionMode = hdrConversionMode.getConversionMode(); + int preferredHdrType = hdrConversionMode.getPreferredHdrOutputType(); // If the HDR conversion is disabled by an app through WindowManager.LayoutParams, then // set HDR conversion mode to HDR_CONVERSION_PASSTHROUGH. if (mOverrideHdrConversionMode == null) { - mSystemPreferredHdrOutputType = - mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(), - hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes); + // HDR_CONVERSION_FORCE with HDR_TYPE_INVALID is used to represent forcing SDR type. + // But, internally SDR is selected by using passthrough mode. + if (conversionMode == HdrConversionMode.HDR_CONVERSION_FORCE + && preferredHdrType == Display.HdrCapabilities.HDR_TYPE_INVALID) { + conversionMode = HdrConversionMode.HDR_CONVERSION_PASSTHROUGH; + } } else { - mInjector.setHdrConversionMode(mOverrideHdrConversionMode.getConversionMode(), - mOverrideHdrConversionMode.getPreferredHdrOutputType(), null); + conversionMode = mOverrideHdrConversionMode.getConversionMode(); + preferredHdrType = mOverrideHdrConversionMode.getPreferredHdrOutputType(); + autoHdrOutputTypes = null; } + mSystemPreferredHdrOutputType = mInjector.setHdrConversionMode( + conversionMode, preferredHdrType, autoHdrOutputTypes); } } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 58c50346a38f..8d0689ff8fe5 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -42,6 +42,7 @@ import android.view.DisplayShape; import android.view.RoundedCorners; import android.view.SurfaceControl; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.util.function.pooled.PooledLambda; @@ -675,14 +676,13 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.flags |= DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY; if (mIsFirstDisplay) { - if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound) + if (res.getBoolean(R.bool.config_mainBuiltInDisplayIsRound) || (Build.IS_EMULATOR && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND; } } else { - if (!res.getBoolean( - com.android.internal.R.bool.config_localDisplaysMirrorContent)) { + if (!res.getBoolean(R.bool.config_localDisplaysMirrorContent)) { mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; } @@ -711,18 +711,23 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.displayShape = DisplayShape.fromResources( res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height); + mInfo.name = getDisplayDeviceConfig().getName(); + if (mStaticDisplayInfo.isInternal) { mInfo.type = Display.TYPE_INTERNAL; mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; - mInfo.name = res.getString( - com.android.internal.R.string.display_manager_built_in_display_name); + if (mInfo.name == null) { + mInfo.name = res.getString(R.string.display_manager_built_in_display_name); + } } else { mInfo.type = Display.TYPE_EXTERNAL; mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; - mInfo.name = getContext().getResources().getString( - com.android.internal.R.string.display_manager_hdmi_display_name); + if (mInfo.name == null) { + mInfo.name = getContext().getResources().getString( + R.string.display_manager_hdmi_display_name); + } } mInfo.frameRateOverrides = mFrameRateOverrides; @@ -1255,8 +1260,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { return false; } final Resources res = getOverlayContext().getResources(); - int[] ports = res.getIntArray( - com.android.internal.R.array.config_localPrivateDisplayPorts); + int[] ports = res.getIntArray(R.array.config_localPrivateDisplayPorts); if (ports != null) { int port = physicalAddress.getPort(); for (int p : ports) { diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 78c597ea6e53..dee4cdea65fe 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -189,7 +189,7 @@ final class LogicalDisplay { mTempFrameRateOverride = new SparseArray<>(); mIsEnabled = true; mIsInTransition = false; - mBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID; + mBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; } public void setDevicePositionLocked(int position) { @@ -344,6 +344,21 @@ final class LogicalDisplay { mInfo.set(null); } } + /** + * Updates refreshRateThermalThrottling + * + * @param refreshRanges new refreshRateThermalThrottling ranges limited by layout or default + */ + public void updateRefreshRateThermalThrottling( + @Nullable SparseArray<SurfaceControl.RefreshRateRange> refreshRanges) { + if (refreshRanges == null) { + refreshRanges = new SparseArray<>(); + } + if (!mBaseDisplayInfo.refreshRateThermalThrottling.contentEquals(refreshRanges)) { + mBaseDisplayInfo.refreshRateThermalThrottling = refreshRanges; + mInfo.set(null); + } + } /** * Updates the state of the logical display based on the available display devices. @@ -572,7 +587,7 @@ final class LogicalDisplay { DisplayDevice device, boolean isBlanked) { // Set the layer stack. - device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); + device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack, mDisplayId); // Also inform whether the device is the same one sent to inputflinger for its layerstack. // Prevent displays that are disabled from receiving input. // TODO(b/188914255): Remove once input can dispatch against device vs layerstack. diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 2ac7d9d1a73e..e290b7a8b708 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -1013,19 +1013,23 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (newDisplay != oldDisplay) { newDisplay.swapDisplaysLocked(oldDisplay); } + DisplayDeviceConfig config = device.getDisplayDeviceConfig(); newDisplay.setDevicePositionLocked(displayLayout.getPosition()); newDisplay.setLeadDisplayLocked(displayLayout.getLeadDisplayId()); newDisplay.updateLayoutLimitedRefreshRateLocked( - device.getDisplayDeviceConfig().getRefreshRange( - displayLayout.getRefreshRateZoneId() + config.getRefreshRange(displayLayout.getRefreshRateZoneId()) + ); + newDisplay.updateRefreshRateThermalThrottling( + config.getRefreshRateThrottlingData( + displayLayout.getRefreshRateThermalThrottlingMapId() ) ); setEnabledLocked(newDisplay, displayLayout.isEnabled()); newDisplay.setBrightnessThrottlingDataIdLocked( displayLayout.getBrightnessThrottlingMapId() == null - ? DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID + ? DisplayDeviceConfig.DEFAULT_ID : displayLayout.getBrightnessThrottlingMapId()); newDisplay.setDisplayGroupNameLocked(displayLayout.getDisplayGroupName()); diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 364d53ba3c10..eda15ae32c8b 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -285,7 +285,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mUniqueIndex = uniqueIndex; mIsDisplayOn = surface != null; mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror(); - mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroring(); + mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroringEnabled(); } @Override diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java index f1e885e982e1..6a4d23b18763 100644 --- a/services/core/java/com/android/server/display/layout/Layout.java +++ b/services/core/java/com/android/server/display/layout/Layout.java @@ -257,6 +257,9 @@ public class Layout { @Nullable private String mRefreshRateZoneId; + @Nullable + private String mRefreshRateThermalThrottlingMapId; + Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled, @NonNull String displayGroupName, String brightnessThrottlingMapId, int position, int leadDisplayId) { @@ -286,6 +289,7 @@ public class Layout { + ", brightnessThrottlingMapId: " + mBrightnessThrottlingMapId + ", mRefreshRateZoneId: " + mRefreshRateZoneId + ", mLeadDisplayId: " + mLeadDisplayId + + ", mRefreshRateThermalThrottlingMapId: " + mRefreshRateThermalThrottlingMapId + "}"; } @@ -305,7 +309,9 @@ public class Layout { && Objects.equals(mBrightnessThrottlingMapId, otherDisplay.mBrightnessThrottlingMapId) && Objects.equals(otherDisplay.mRefreshRateZoneId, this.mRefreshRateZoneId) - && this.mLeadDisplayId == otherDisplay.mLeadDisplayId; + && this.mLeadDisplayId == otherDisplay.mLeadDisplayId + && Objects.equals(mRefreshRateThermalThrottlingMapId, + otherDisplay.mRefreshRateThermalThrottlingMapId); } @Override @@ -319,6 +325,7 @@ public class Layout { result = 31 * result + mBrightnessThrottlingMapId.hashCode(); result = 31 * result + Objects.hashCode(mRefreshRateZoneId); result = 31 * result + mLeadDisplayId; + result = 31 * result + Objects.hashCode(mRefreshRateThermalThrottlingMapId); return result; } @@ -388,5 +395,13 @@ public class Layout { public int getLeadDisplayId() { return mLeadDisplayId; } + + public void setRefreshRateThermalThrottlingMapId(String refreshRateThermalThrottlingMapId) { + mRefreshRateThermalThrottlingMapId = refreshRateThermalThrottlingMapId; + } + + public String getRefreshRateThermalThrottlingMapId() { + return mRefreshRateThermalThrottlingMapId; + } } } diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 24d5ca402dd0..db6944d011c9 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -224,6 +224,7 @@ public class DisplayModeDirector { } mLoggingEnabled = loggingEnabled; mBrightnessObserver.setLoggingEnabled(loggingEnabled); + mSkinThermalStatusObserver.setLoggingEnabled(loggingEnabled); } @NonNull @@ -2669,7 +2670,7 @@ public class DisplayModeDirector { } } - private static final class SensorObserver implements ProximityActiveListener, + protected static final class SensorObserver implements ProximityActiveListener, DisplayManager.DisplayListener { private final String mProximitySensorName = null; private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY; @@ -2952,52 +2953,6 @@ public class DisplayModeDirector { } } - private final class SkinThermalStatusObserver extends IThermalEventListener.Stub { - private final BallotBox mBallotBox; - private final Injector mInjector; - - private @Temperature.ThrottlingStatus int mStatus = -1; - - SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) { - mInjector = injector; - mBallotBox = ballotBox; - } - - @Override - public void notifyThrottling(Temperature temp) { - mStatus = temp.getStatus(); - if (mLoggingEnabled) { - Slog.d(TAG, "New thermal throttling status " - + ", current thermal status = " + mStatus); - } - final Vote vote; - if (mStatus >= Temperature.THROTTLING_CRITICAL) { - vote = Vote.forRenderFrameRates(0f, 60f); - } else { - vote = null; - } - mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote); - } - - public void observe() { - IThermalService thermalService = mInjector.getThermalService(); - if (thermalService == null) { - Slog.w(TAG, "Could not observe thermal status. Service not available"); - return; - } - try { - thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to register thermal status listener", e); - } - } - - void dumpLocked(PrintWriter writer) { - writer.println(" SkinThermalStatusObserver:"); - writer.println(" mStatus: " + mStatus); - } - } - private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public void startListening() { mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, @@ -3184,11 +3139,15 @@ public class DisplayModeDirector { void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, Handler handler, long flags); + Display[] getDisplays(); + + boolean getDisplayInfo(int displayId, DisplayInfo displayInfo); + BrightnessInfo getBrightnessInfo(int displayId); boolean isDozeState(Display d); - IThermalService getThermalService(); + boolean registerThermalServiceListener(IThermalEventListener listener); boolean supportsFrameRateOverride(); } @@ -3222,6 +3181,20 @@ public class DisplayModeDirector { } @Override + public Display[] getDisplays() { + return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED); + } + + @Override + public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { + Display display = getDisplayManager().getDisplay(displayId); + if (display != null) { + return display.getDisplayInfo(displayInfo); + } + return false; + } + + @Override public BrightnessInfo getBrightnessInfo(int displayId) { final Display display = getDisplayManager().getDisplay(displayId); if (display != null) { @@ -3239,9 +3212,20 @@ public class DisplayModeDirector { } @Override - public IThermalService getThermalService() { - return IThermalService.Stub.asInterface( - ServiceManager.getService(Context.THERMAL_SERVICE)); + public boolean registerThermalServiceListener(IThermalEventListener listener) { + IThermalService thermalService = getThermalService(); + if (thermalService == null) { + Slog.w(TAG, "Could not observe thermal status. Service not available"); + return false; + } + try { + thermalService.registerThermalEventListenerWithType(listener, + Temperature.TYPE_SKIN); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register thermal status listener", e); + return false; + } + return true; } @Override @@ -3255,6 +3239,11 @@ public class DisplayModeDirector { } return mDisplayManager; } + + private IThermalService getThermalService() { + return IThermalService.Stub.asInterface( + ServiceManager.getService(Context.THERMAL_SERVICE)); + } } interface BallotBox { diff --git a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java new file mode 100644 index 000000000000..1bb34abe9025 --- /dev/null +++ b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java @@ -0,0 +1,263 @@ +/* + * 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.display.mode; + +import android.annotation.Nullable; +import android.hardware.display.DisplayManager; +import android.os.Handler; +import android.os.IThermalEventListener; +import android.os.Temperature; +import android.util.Slog; +import android.util.SparseArray; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.SurfaceControl; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; + +import java.io.PrintWriter; + +final class SkinThermalStatusObserver extends IThermalEventListener.Stub implements + DisplayManager.DisplayListener { + private static final String TAG = "SkinThermalStatusObserver"; + + private final DisplayModeDirector.BallotBox mBallotBox; + private final DisplayModeDirector.Injector mInjector; + + private boolean mLoggingEnabled; + + private final Handler mHandler; + private final Object mThermalObserverLock = new Object(); + @GuardedBy("mThermalObserverLock") + @Temperature.ThrottlingStatus + private int mStatus = -1; + @GuardedBy("mThermalObserverLock") + private final SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> + mThermalThrottlingByDisplay = new SparseArray<>(); + + SkinThermalStatusObserver(DisplayModeDirector.Injector injector, + DisplayModeDirector.BallotBox ballotBox) { + this(injector, ballotBox, BackgroundThread.getHandler()); + } + + @VisibleForTesting + SkinThermalStatusObserver(DisplayModeDirector.Injector injector, + DisplayModeDirector.BallotBox ballotBox, Handler handler) { + mInjector = injector; + mBallotBox = ballotBox; + mHandler = handler; + } + + void observe() { + // if failed to register thermal service listener, don't register display listener + if (!mInjector.registerThermalServiceListener(this)) { + return; + } + + mInjector.registerDisplayListener(this, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_ADDED | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); + + populateInitialDisplayInfo(); + } + + void setLoggingEnabled(boolean enabled) { + mLoggingEnabled = enabled; + } + + @Override + public void notifyThrottling(Temperature temp) { + @Temperature.ThrottlingStatus int currentStatus = temp.getStatus(); + synchronized (mThermalObserverLock) { + mStatus = currentStatus; + mHandler.post(this::updateVotes); + } + + if (mLoggingEnabled) { + Slog.d(TAG, "New thermal throttling status " + ", current thermal status = " + + currentStatus); + } + } + + //region DisplayManager.DisplayListener + @Override + public void onDisplayAdded(int displayId) { + updateRefreshRateThermalThrottling(displayId); + if (mLoggingEnabled) { + Slog.d(TAG, "Display added:" + displayId); + } + } + + @Override + public void onDisplayRemoved(int displayId) { + synchronized (mThermalObserverLock) { + mThermalThrottlingByDisplay.remove(displayId); + mHandler.post(() -> mBallotBox.vote(displayId, + DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, null)); + } + if (mLoggingEnabled) { + Slog.d(TAG, "Display removed and voted: displayId=" + displayId); + } + } + + @Override + public void onDisplayChanged(int displayId) { + updateRefreshRateThermalThrottling(displayId); + if (mLoggingEnabled) { + Slog.d(TAG, "Display changed:" + displayId); + } + } + //endregion + + private void populateInitialDisplayInfo() { + DisplayInfo info = new DisplayInfo(); + Display[] displays = mInjector.getDisplays(); + int size = displays.length; + SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> localMap = new SparseArray<>( + size); + for (Display d : displays) { + final int displayId = d.getDisplayId(); + d.getDisplayInfo(info); + localMap.put(displayId, info.refreshRateThermalThrottling); + } + synchronized (mThermalObserverLock) { + for (int i = 0; i < size; i++) { + mThermalThrottlingByDisplay.put(localMap.keyAt(i), localMap.valueAt(i)); + } + } + if (mLoggingEnabled) { + Slog.d(TAG, "Display initial info:" + localMap); + } + } + + private void updateRefreshRateThermalThrottling(int displayId) { + DisplayInfo displayInfo = new DisplayInfo(); + mInjector.getDisplayInfo(displayId, displayInfo); + SparseArray<SurfaceControl.RefreshRateRange> throttlingMap = + displayInfo.refreshRateThermalThrottling; + + synchronized (mThermalObserverLock) { + mThermalThrottlingByDisplay.put(displayId, throttlingMap); + mHandler.post(() -> updateVoteForDisplay(displayId)); + } + if (mLoggingEnabled) { + Slog.d(TAG, + "Thermal throttling updated: display=" + displayId + ", map=" + throttlingMap); + } + } + + //region in mHandler thread + private void updateVotes() { + @Temperature.ThrottlingStatus int localStatus; + SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> localMap; + + synchronized (mThermalObserverLock) { + localStatus = mStatus; + localMap = mThermalThrottlingByDisplay.clone(); + } + if (mLoggingEnabled) { + Slog.d(TAG, "Updating votes for status=" + localStatus + ", map=" + localMap); + } + int size = localMap.size(); + for (int i = 0; i < size; i++) { + reportThrottlingIfNeeded(localMap.keyAt(i), localStatus, localMap.valueAt(i)); + } + } + + private void updateVoteForDisplay(int displayId) { + @Temperature.ThrottlingStatus int localStatus; + SparseArray<SurfaceControl.RefreshRateRange> localMap; + + synchronized (mThermalObserverLock) { + localStatus = mStatus; + localMap = mThermalThrottlingByDisplay.get(displayId); + } + if (mLoggingEnabled) { + Slog.d(TAG, "Updating votes for status=" + localStatus + ", display =" + displayId + + ", map=" + localMap); + } + reportThrottlingIfNeeded(displayId, localStatus, localMap); + } + + private void reportThrottlingIfNeeded(int displayId, + @Temperature.ThrottlingStatus int currentStatus, + SparseArray<SurfaceControl.RefreshRateRange> throttlingMap) { + if (currentStatus == -1) { // no throttling status reported from thermal sensor yet + return; + } + + if (throttlingMap.size() == 0) { // map is not configured, using default behaviour + fallbackReportThrottlingIfNeeded(displayId, currentStatus); + return; + } + + SurfaceControl.RefreshRateRange foundRange = findBestMatchingRefreshRateRange(currentStatus, + throttlingMap); + // if status <= currentStatus not found in the map reset vote + DisplayModeDirector.Vote vote = null; + if (foundRange != null) { // otherwise vote with found range + vote = DisplayModeDirector.Vote.forRenderFrameRates(foundRange.min, foundRange.max); + } + mBallotBox.vote(displayId, DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, vote); + if (mLoggingEnabled) { + Slog.d(TAG, "Voted: vote=" + vote + ", display =" + displayId); + } + } + + @Nullable + private SurfaceControl.RefreshRateRange findBestMatchingRefreshRateRange( + @Temperature.ThrottlingStatus int currentStatus, + SparseArray<SurfaceControl.RefreshRateRange> throttlingMap) { + SurfaceControl.RefreshRateRange foundRange = null; + for (int status = currentStatus; status >= 0; status--) { + foundRange = throttlingMap.get(status); + if (foundRange != null) { + break; + } + } + return foundRange; + } + + private void fallbackReportThrottlingIfNeeded(int displayId, + @Temperature.ThrottlingStatus int currentStatus) { + DisplayModeDirector.Vote vote = null; + if (currentStatus >= Temperature.THROTTLING_CRITICAL) { + vote = DisplayModeDirector.Vote.forRenderFrameRates(0f, 60f); + } + mBallotBox.vote(displayId, DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, vote); + if (mLoggingEnabled) { + Slog.d(TAG, "Voted(fallback): vote=" + vote + ", display =" + displayId); + } + } + //endregion + + void dumpLocked(PrintWriter writer) { + @Temperature.ThrottlingStatus int localStatus; + SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> localMap; + + synchronized (mThermalObserverLock) { + localStatus = mStatus; + localMap = mThermalThrottlingByDisplay.clone(); + } + + writer.println(" SkinThermalStatusObserver:"); + writer.println(" mStatus: " + localStatus); + writer.println(" mThermalThrottlingByDisplay: " + localMap); + } +} diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index e0253fc3d30c..088740e83c42 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -150,6 +150,10 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener { @Override public void onInputDeviceAdded(int deviceId) { onInputDeviceChanged(deviceId); + if (useNewSettingsUi()) { + // Force native callback to set up keyboard layout overlay for newly added keyboards + reloadKeyboardLayouts(); + } } @Override @@ -283,7 +287,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener { public KeyboardLayout[] getKeyboardLayoutsForInputDevice( final InputDeviceIdentifier identifier) { if (useNewSettingsUi()) { - return new KeyboardLayout[0]; + // Provide all supported keyboard layouts since Ime info is not provided + return getKeyboardLayouts(); } final String[] enabledLayoutDescriptors = getEnabledKeyboardLayoutsForInputDevice(identifier); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index d397a0c5e0bc..91f91f86d275 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3325,6 +3325,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) { ImeTracker.forLogging().onFailed( statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return false; } final long ident = Binder.clearCallingIdentity(); @@ -6458,19 +6459,21 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub 0 /* flags */, null /* resultReceiver */, SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND); mBindingController.unbindCurrentMethod(); - // Reset the current IME - resetSelectedInputMethodAndSubtypeLocked(null); - // Also reset the settings of the current IME - mSettings.putSelectedInputMethod(null); - // Disable all enabled IMEs. - for (InputMethodInfo inputMethodInfo : - mSettings.getEnabledInputMethodListLocked()) { - setInputMethodEnabledLocked(inputMethodInfo.getId(), false); + + // Enable default IMEs, disable others + var toDisable = mSettings.getEnabledInputMethodListLocked(); + var defaultEnabled = InputMethodInfoUtils.getDefaultEnabledImes( + mContext, mMethodList); + toDisable.removeAll(defaultEnabled); + for (InputMethodInfo info : toDisable) { + setInputMethodEnabledLocked(info.getId(), false); + } + for (InputMethodInfo info : defaultEnabled) { + setInputMethodEnabledLocked(info.getId(), true); } - // Re-enable with default enabled IMEs. - for (InputMethodInfo imi : InputMethodInfoUtils.getDefaultEnabledImes( - mContext, mMethodList)) { - setInputMethodEnabledLocked(imi.getId(), true); + // Choose new default IME, reset to none if no IME available. + if (!chooseNewDefaultIMELocked()) { + resetSelectedInputMethodAndSubtypeLocked(null); } updateInputMethodsFromSettingsLocked(true /* enabledMayChange */); InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed( diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java index ca184ee09907..1e32ad613eba 100644 --- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java +++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java @@ -18,6 +18,7 @@ package com.android.server.location.contexthub; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.contexthub.HostEndpointInfo; +import android.hardware.contexthub.NanSessionRequest; import android.hardware.contexthub.V1_0.ContextHub; import android.hardware.contexthub.V1_0.ContextHubMsg; import android.hardware.contexthub.V1_0.TransactionResult; @@ -456,8 +457,8 @@ public abstract class IContextHubWrapper { }); } - public void handleNanSessionRequest(boolean enable) { - // TODO(229888878): Implement + public void handleNanSessionRequest(NanSessionRequest request) { + // TODO(271471342): Implement } @Override diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 2174f4044ffd..c962bc4c20d8 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -295,6 +295,7 @@ public class GnssManagerService { } ipw.println("Capabilities: " + mGnssNative.getCapabilities()); + ipw.println("GNSS Hardware Model Name: " + getGnssHardwareModelName()); if (mGnssStatusProvider.isSupported()) { ipw.println("Status Provider:"); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 5a832b78487c..cc41207eaee1 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -33,7 +33,6 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN; -import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; @@ -82,7 +81,6 @@ import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.net.Uri; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -117,7 +115,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; -import android.util.Log; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; @@ -201,7 +198,6 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String TAG = "LockSettingsService"; private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE; private static final String BIOMETRIC_PERMISSION = MANAGE_BIOMETRIC; - private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG); private static final int PROFILE_KEY_IV_SIZE = 12; private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; @@ -381,7 +377,6 @@ public class LockSettingsService extends ILockSettings.Stub { */ private void tieProfileLockIfNecessary(int profileUserId, LockscreenCredential profileUserPassword) { - if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + profileUserId); // Only for profiles that shares credential with parent if (!isCredentialSharableWithParent(profileUserId)) { return; @@ -399,8 +394,7 @@ public class LockSettingsService extends ILockSettings.Stub { // as its parent. final int parentId = mUserManager.getProfileParent(profileUserId).id; if (!isUserSecure(parentId) && !profileUserPassword.isNone()) { - if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock but profile has one"); - + Slogf.i(TAG, "Clearing password for profile user %d to match parent", profileUserId); setLockCredentialInternal(LockscreenCredential.createNone(), profileUserPassword, profileUserId, /* isLockTiedToParent= */ true); return; @@ -416,7 +410,6 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.e(TAG, "Failed to talk to GateKeeper service", e); return; } - if (DEBUG) Slog.v(TAG, "Tie profile to parent now!"); try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) { setLockCredentialInternal(unifiedProfilePassword, profileUserPassword, profileUserId, /* isLockTiedToParent= */ true); @@ -690,8 +683,8 @@ public class LockSettingsService extends ILockSettings.Stub { PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED); - Slog.d(TAG, TextUtils.formatSimple("showing encryption notification, user: %d; reason: %s", - user.getIdentifier(), reason)); + Slogf.d(TAG, "Showing encryption notification for user %d; reason: %s", + user.getIdentifier(), reason); showEncryptionNotification(user, title, message, detail, intent); } @@ -735,7 +728,7 @@ public class LockSettingsService extends ILockSettings.Stub { } private void hideEncryptionNotification(UserHandle userHandle) { - Slog.d(TAG, "hide encryption notification, user: " + userHandle.getIdentifier()); + Slogf.d(TAG, "Hiding encryption notification for user %d", userHandle.getIdentifier()); mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION, userHandle); } @@ -888,7 +881,6 @@ public class LockSettingsService extends ILockSettings.Stub { && !getBoolean("migrated_frp", false, 0)) { migrateFrpCredential(); setBoolean("migrated_frp", true, 0); - Slog.i(TAG, "Migrated migrated_frp."); } } @@ -1034,7 +1026,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void enforceFrpResolved() { final int mainUserId = mInjector.getUserManagerInternal().getMainUserId(); if (mainUserId < 0) { - Slog.i(TAG, "No Main user on device; skip enforceFrpResolved"); + Slog.d(TAG, "No Main user on device; skipping enforceFrpResolved"); return; } final ContentResolver cr = mContext.getContentResolver(); @@ -1269,7 +1261,6 @@ public class LockSettingsService extends ILockSettings.Stub { } private void unlockKeystore(byte[] password, int userHandle) { - if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); Authorization.onLockScreenEvent(false, userHandle, password, null); } @@ -1279,7 +1270,7 @@ public class LockSettingsService extends ILockSettings.Stub { NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, CertificateException, IOException { - if (DEBUG) Slog.v(TAG, "Get child profile decrypted key"); + Slogf.d(TAG, "Decrypting password for tied profile %d", userId); byte[] storedData = mStorage.readChildProfileLock(userId); if (storedData == null) { throw new FileNotFoundException("Child profile lock file not found"); @@ -1328,7 +1319,6 @@ public class LockSettingsService extends ILockSettings.Stub { * {@link com.android.server.SystemServiceManager#unlockUser} </em> */ private void unlockUser(@UserIdInt int userId) { - Slogf.i(TAG, "Unlocking user %d", userId); // TODO: make this method fully async so we can update UI with progress strings final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId); final CountDownLatch latch = new CountDownLatch(1); @@ -1638,7 +1628,6 @@ public class LockSettingsService extends ILockSettings.Stub { LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { Objects.requireNonNull(credential); Objects.requireNonNull(savedCredential); - if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId); synchronized (mSpManager) { if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) { // get credential from keystore when profile has unified lock @@ -1720,6 +1709,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (passwordHistoryLength == 0) { passwordHistory = ""; } else { + Slogf.d(TAG, "Adding new password to password history for user %d", userHandle); final byte[] hashFactor = getHashFactor(password, userHandle); final byte[] salt = getSalt(userHandle).getBytes(); String hash = password.passwordToHistoryHash(salt, hashFactor); @@ -1751,7 +1741,6 @@ public class LockSettingsService extends ILockSettings.Stub { if (salt == 0) { salt = SecureRandomUtils.randomLong(); setLong(LockPatternUtils.LOCK_PASSWORD_SALT_KEY, salt, userId); - Slog.v(TAG, "Initialized lock password salt for user: " + userId); } return Long.toHexString(salt); } @@ -1875,7 +1864,8 @@ public class LockSettingsService extends ILockSettings.Stub { @VisibleForTesting /** Note: this method is overridden in unit tests */ protected void tieProfileLockToParent(int profileUserId, int parentUserId, LockscreenCredential password) { - if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + profileUserId); + Slogf.i(TAG, "Tying lock for profile user %d to parent user %d", profileUserId, + parentUserId); final byte[] iv; final byte[] ciphertext; final long parentSid; @@ -2002,7 +1992,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void resetKeyStore(int userId) { checkWritePermission(); - if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); + Slogf.d(TAG, "Resetting keystore for user %d", userId); List<Integer> profileUserIds = new ArrayList<>(); List<LockscreenCredential> profileUserDecryptedPasswords = new ArrayList<>(); final List<UserInfo> profiles = mUserManager.getProfiles(userId); @@ -2039,7 +2029,6 @@ public class LockSettingsService extends ILockSettings.Stub { int piUserId = profileUserIds.get(i); LockscreenCredential piUserDecryptedPassword = profileUserDecryptedPasswords.get(i); if (piUserId != -1 && piUserDecryptedPassword != null) { - if (DEBUG) Slog.v(TAG, "Restore tied profile lock"); tieProfileLockToParent(piUserId, userId, piUserDecryptedPassword); } if (piUserDecryptedPassword != null) { @@ -2132,7 +2121,7 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.e(TAG, "FRP credential can only be verified prior to provisioning."); return VerifyCredentialResponse.ERROR; } - Slog.d(TAG, "doVerifyCredential: user=" + userId); + Slogf.i(TAG, "Verifying lockscreen credential for user %d", userId); final AuthenticationResult authResult; VerifyCredentialResponse response; @@ -2166,6 +2155,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + Slogf.i(TAG, "Successfully verified lockscreen credential for user %d", userId); onCredentialVerified(authResult.syntheticPassword, PasswordMetrics.computeForCredential(credential), userId); if ((flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0) { @@ -2324,13 +2314,18 @@ public class LockSettingsService extends ILockSettings.Stub { } private void removeKeystoreProfileKey(int targetUserId) { - Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId); + final String encryptAlias = PROFILE_KEY_NAME_ENCRYPT + targetUserId; + final String decryptAlias = PROFILE_KEY_NAME_DECRYPT + targetUserId; try { - mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + targetUserId); - mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_DECRYPT + targetUserId); + if (mJavaKeyStore.containsAlias(encryptAlias) || + mJavaKeyStore.containsAlias(decryptAlias)) { + Slogf.i(TAG, "Removing keystore profile key for user %d", targetUserId); + mJavaKeyStore.deleteEntry(encryptAlias); + mJavaKeyStore.deleteEntry(decryptAlias); + } } catch (KeyStoreException e) { - // We have tried our best to remove all keys - Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e); + // We have tried our best to remove the key. + Slogf.e(TAG, e, "Error removing keystore profile key for user %d", targetUserId); } } @@ -2678,7 +2673,7 @@ public class LockSettingsService extends ILockSettings.Stub { @VisibleForTesting SyntheticPassword initializeSyntheticPassword(int userId) { synchronized (mSpManager) { - Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); + Slogf.i(TAG, "Initializing synthetic password for user %d", userId); Preconditions.checkState(getCurrentLskfBasedProtectorId(userId) == SyntheticPasswordManager.NULL_PROTECTOR_ID, "Cannot reinitialize SP"); @@ -2689,6 +2684,7 @@ public class LockSettingsService extends ILockSettings.Stub { setCurrentLskfBasedProtectorId(protectorId, userId); setUserKeyProtection(userId, sp.deriveFileBasedEncryptionKey()); onSyntheticPasswordCreated(userId, sp); + Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId); return sp; } } @@ -2725,8 +2721,11 @@ public class LockSettingsService extends ILockSettings.Stub { final long finalHandle = handle; mHandler.postDelayed(() -> { synchronized (mGatekeeperPasswords) { - Slog.d(TAG, "Removing handle: " + finalHandle); - mGatekeeperPasswords.remove(finalHandle); + if (mGatekeeperPasswords.get(finalHandle) != null) { + Slogf.d(TAG, "Cached Gatekeeper password with handle %016x has expired", + finalHandle); + mGatekeeperPasswords.remove(finalHandle); + } } }, GK_PW_HANDLE_STORE_DURATION_MS); @@ -2775,7 +2774,8 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") private long setLockCredentialWithSpLocked(LockscreenCredential credential, SyntheticPassword sp, int userId) { - if (DEBUG) Slog.d(TAG, "setLockCredentialWithSpLocked: user=" + userId); + Slogf.i(TAG, "Changing lockscreen credential of user %d; newCredentialType=%s\n", + userId, LockPatternUtils.credentialTypeToString(credential.getType())); final int savedCredentialType = getCredentialTypeInternal(userId); final long oldProtectorId = getCurrentLskfBasedProtectorId(userId); final long newProtectorId = mSpManager.createLskfBasedProtector(getGateKeeperService(), @@ -2820,6 +2820,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } mSpManager.destroyLskfBasedProtector(oldProtectorId, userId); + Slogf.i(TAG, "Successfully changed lockscreen credential of user %d", userId); return newProtectorId; } @@ -2904,6 +2905,7 @@ public class LockSettingsService extends ILockSettings.Stub { public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) { checkPasswordReadPermission(); try { + Slogf.d(TAG, "Getting password history hash factor for user %d", userId); if (isProfileWithUnifiedLock(userId)) { try { currentCredential = getDecryptedPasswordForTiedProfile(userId); @@ -2929,7 +2931,7 @@ public class LockSettingsService extends ILockSettings.Stub { private long addEscrowToken(@NonNull byte[] token, @TokenType int type, int userId, @NonNull EscrowTokenStateChangeCallback callback) { - if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId + ", type=" + type); + Slogf.i(TAG, "Adding escrow token for user %d", userId); synchronized (mSpManager) { // If the user has no LSKF, then the token can be activated immediately. Otherwise, the // token can't be activated until the SP is unlocked by another protector (normally the @@ -2947,18 +2949,20 @@ public class LockSettingsService extends ILockSettings.Stub { long handle = mSpManager.addPendingToken(token, type, userId, callback); if (sp != null) { // Activate the token immediately + Slogf.i(TAG, "Immediately activating escrow token %016x", handle); mSpManager.createTokenBasedProtector(handle, sp, userId); + } else { + Slogf.i(TAG, "Escrow token %016x will be activated when user is unlocked", handle); } return handle; } } private void activateEscrowTokens(SyntheticPassword sp, int userId) { - if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId); synchronized (mSpManager) { disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); for (long handle : mSpManager.getPendingTokensForUser(userId)) { - Slog.i(TAG, TextUtils.formatSimple("activateEscrowTokens: %x %d ", handle, userId)); + Slogf.i(TAG, "Activating escrow token %016x for user %d", handle, userId); mSpManager.createTokenBasedProtector(handle, sp, userId); } } @@ -3029,6 +3033,8 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") private boolean setLockCredentialWithTokenInternalLocked(LockscreenCredential credential, long tokenHandle, byte[] token, int userId) { + Slogf.i(TAG, "Resetting lockscreen credential of user %d using escrow token %016x", + userId, tokenHandle); final AuthenticationResult result; result = mSpManager.unlockTokenBasedProtector(getGateKeeperService(), tokenHandle, token, userId); @@ -3051,8 +3057,9 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) { AuthenticationResult authResult; synchronized (mSpManager) { + Slogf.i(TAG, "Unlocking user %d using escrow token %016x", userId, tokenHandle); if (!mSpManager.hasEscrowData(userId)) { - Slog.w(TAG, "Escrow token is disabled on the current user"); + Slogf.w(TAG, "Escrow token support is disabled on user %d", userId); return false; } authResult = mSpManager.unlockTokenBasedProtector(getGateKeeperService(), tokenHandle, @@ -3063,6 +3070,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } + Slogf.i(TAG, "Unlocked synthetic password for user %d using escrow token", userId); onCredentialVerified(authResult.syntheticPassword, loadPasswordMetrics(authResult.syntheticPassword, userId), userId); return true; @@ -3090,24 +3098,19 @@ public class LockSettingsService extends ILockSettings.Stub { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp)); } - private static String credentialTypeToString(int credentialType) { - switch (credentialType) { - case CREDENTIAL_TYPE_NONE: - return "None"; - case CREDENTIAL_TYPE_PATTERN: - return "Pattern"; - case CREDENTIAL_TYPE_PIN: - return "Pin"; - case CREDENTIAL_TYPE_PASSWORD: - return "Password"; - default: - return "Unknown " + credentialType; - } - } - @Override protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return; + + final long identity = Binder.clearCallingIdentity(); + try { + dumpInternal(printWriter); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + private void dumpInternal(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("Current lock settings service state:"); @@ -3121,22 +3124,23 @@ public class LockSettingsService extends ILockSettings.Stub { pw.println("User " + userId); pw.increaseIndent(); synchronized (mSpManager) { - pw.println(TextUtils.formatSimple("LSKF-based SP protector ID: %x", + pw.println(TextUtils.formatSimple("LSKF-based SP protector ID: %016x", getCurrentLskfBasedProtectorId(userId))); - pw.println(TextUtils.formatSimple("LSKF last changed: %s (previous protector: %x)", - timestampToString(getLong(LSKF_LAST_CHANGED_TIME_KEY, 0, userId)), - getLong(PREV_LSKF_BASED_PROTECTOR_ID_KEY, 0, userId))); + pw.println(TextUtils.formatSimple( + "LSKF last changed: %s (previous protector: %016x)", + timestampToString(getLong(LSKF_LAST_CHANGED_TIME_KEY, 0, userId)), + getLong(PREV_LSKF_BASED_PROTECTOR_ID_KEY, 0, userId))); } try { - pw.println(TextUtils.formatSimple("SID: %x", + pw.println(TextUtils.formatSimple("SID: %016x", getGateKeeperService().getSecureUserId(userId))); } catch (RemoteException e) { // ignore. } - // It's OK to dump the password type since anyone with physical access can just + // It's OK to dump the credential type since anyone with physical access can just // observe it from the keyguard directly. pw.println("Quality: " + getKeyguardStoredQuality(userId)); - pw.println("CredentialType: " + credentialTypeToString( + pw.println("CredentialType: " + LockPatternUtils.credentialTypeToString( getCredentialTypeInternal(userId))); pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabledInternal(userId)); pw.println(TextUtils.formatSimple("Metrics: %s", @@ -3194,6 +3198,11 @@ public class LockSettingsService extends ILockSettings.Stub { * if we are running an automotive build. */ private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) { + + if (!mSpManager.hasAnyEscrowData(userId)) { + return; + } + // TODO(b/258213147): Remove final long identity = Binder.clearCallingIdentity(); try { @@ -3238,7 +3247,7 @@ public class LockSettingsService extends ILockSettings.Stub { } // Disable escrow token permanently on all other device/user types. - Slog.i(TAG, "Disabling escrow token on user " + userId); + Slogf.i(TAG, "Permanently disabling support for escrow tokens on user %d", userId); mSpManager.destroyEscrowData(userId); } @@ -3470,6 +3479,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSpManager) { mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId); } + Slogf.i(TAG, "Restored synthetic password for user %d using reboot escrow", userId); onCredentialVerified(sp, loadPasswordMetrics(sp, userId), userId); } } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index d070b416c53c..1663b019d769 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -744,6 +744,11 @@ class SyntheticPasswordManager { && hasState(SP_P1_NAME, NULL_PROTECTOR_ID, userId); } + public boolean hasAnyEscrowData(int userId) { + return hasState(SP_E0_NAME, NULL_PROTECTOR_ID, userId) + || hasState(SP_P1_NAME, NULL_PROTECTOR_ID, userId); + } + public void destroyEscrowData(int userId) { destroyState(SP_E0_NAME, NULL_PROTECTOR_ID, userId); destroyState(SP_P1_NAME, NULL_PROTECTOR_ID, userId); @@ -786,11 +791,11 @@ class SyntheticPasswordManager { } Set<Integer> usedSlots = getUsedWeaverSlots(); if (!usedSlots.contains(slot)) { - Slog.i(TAG, "Destroy weaver slot " + slot + " for user " + userId); + Slogf.i(TAG, "Erasing Weaver slot %d", slot); weaverEnroll(slot, null, null); mPasswordSlotManager.markSlotDeleted(slot); } else { - Slog.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId); + Slogf.i(TAG, "Weaver slot %d was already reused; not erasing it", slot); } } } @@ -858,11 +863,13 @@ class SyntheticPasswordManager { long sid = GateKeeper.INVALID_SECURE_USER_ID; final byte[] protectorSecret; + Slogf.i(TAG, "Creating LSKF-based protector %016x for user %d", protectorId, userId); + if (isWeaverAvailable()) { // Weaver is available, so make the protector use it to verify the LSKF. Do this even // if the LSKF is empty, as that gives us support for securely deleting the protector. int weaverSlot = getNextAvailableWeaverSlot(); - Slog.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId); + Slogf.i(TAG, "Enrolling LSKF for user %d into Weaver slot %d", userId, weaverSlot); byte[] weaverSecret = weaverEnroll(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf), null); if (weaverSecret == null) { @@ -892,6 +899,7 @@ class SyntheticPasswordManager { } catch (RemoteException ignore) { Slog.w(TAG, "Failed to clear SID from gatekeeper"); } + Slogf.i(TAG, "Enrolling LSKF for user %d into Gatekeeper", userId); GateKeeperResponse response; try { response = gatekeeper.enroll(fakeUserId(userId), null, null, @@ -964,6 +972,7 @@ class SyntheticPasswordManager { && LockPatternUtils.userOwnsFrpCredential(mContext, userInfo) && getCredentialType(protectorId, userInfo.id) != LockPatternUtils.CREDENTIAL_TYPE_NONE) { + Slog.i(TAG, "Migrating FRP credential to persistent data block"); PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, protectorId, userInfo.id)); int weaverSlot = loadWeaverSlot(protectorId, userInfo.id); @@ -1092,9 +1101,10 @@ class SyntheticPasswordManager { Slog.w(TAG, "User is not escrowable"); return false; } + Slogf.i(TAG, "Creating token-based protector %016x for user %d", tokenHandle, userId); if (isWeaverAvailable()) { int slot = getNextAvailableWeaverSlot(); - Slog.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId); + Slogf.i(TAG, "Using Weaver slot %d for new token-based protector", slot); if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) { Slog.e(TAG, "Failed to enroll weaver secret when activating token"); return false; @@ -1170,8 +1180,9 @@ class SyntheticPasswordManager { storedType = pwd.credentialType; } if (!credential.checkAgainstStoredType(storedType)) { - Slog.e(TAG, TextUtils.formatSimple("Credential type mismatch: expected %d actual %d", - storedType, credential.getType())); + Slogf.e(TAG, "Credential type mismatch: stored type is %s but provided type is %s", + LockPatternUtils.credentialTypeToString(storedType), + LockPatternUtils.credentialTypeToString(credential.getType())); result.gkResponse = VerifyCredentialResponse.ERROR; return result; } @@ -1473,6 +1484,7 @@ class SyntheticPasswordManager { /** Destroy a token-based SP protector. */ public void destroyTokenBasedProtector(long protectorId, int userId) { + Slogf.i(TAG, "Destroying token-based protector %016x for user %d", protectorId, userId); SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME, protectorId, userId)); destroyProtectorCommon(protectorId, userId); @@ -1498,6 +1510,7 @@ class SyntheticPasswordManager { * Destroy an LSKF-based SP protector. This is used when the user's LSKF is changed. */ public void destroyLskfBasedProtector(long protectorId, int userId) { + Slogf.i(TAG, "Destroying LSKF-based protector %016x for user %d", protectorId, userId); destroyProtectorCommon(protectorId, userId); destroyState(PASSWORD_DATA_NAME, protectorId, userId); destroyState(PASSWORD_METRICS_NAME, protectorId, userId); @@ -1658,6 +1671,9 @@ class SyntheticPasswordManager { } private String getProtectorKeyAlias(long protectorId) { + // Note, this arguably has a bug: %x should be %016x so that the protector ID is left-padded + // with zeroes, like how the synthetic password state files are named. It's too late to fix + // this, though, and it doesn't actually matter. return TextUtils.formatSimple("%s%x", PROTECTOR_KEY_ALIAS_PREFIX, protectorId); } diff --git a/services/core/java/com/android/server/media/AudioAttributesUtils.java b/services/core/java/com/android/server/media/AudioAttributesUtils.java new file mode 100644 index 000000000000..b9c9bae8e62b --- /dev/null +++ b/services/core/java/com/android/server/media/AudioAttributesUtils.java @@ -0,0 +1,112 @@ +/* + * 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.media; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.media.AudioAttributes; +import android.media.AudioDeviceAttributes; +import android.media.AudioDeviceInfo; +import android.media.MediaRoute2Info; + +/* package */ final class AudioAttributesUtils { + + /* package */ static final AudioAttributes ATTRIBUTES_MEDIA = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .build(); + + private AudioAttributesUtils() { + // no-op to prevent instantiation. + } + + @MediaRoute2Info.Type + /* package */ static int mapToMediaRouteType( + @NonNull AudioDeviceAttributes audioDeviceAttributes) { + switch (audioDeviceAttributes.getType()) { + case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE: + case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: + return MediaRoute2Info.TYPE_BUILTIN_SPEAKER; + case AudioDeviceInfo.TYPE_WIRED_HEADSET: + return MediaRoute2Info.TYPE_WIRED_HEADSET; + case AudioDeviceInfo.TYPE_WIRED_HEADPHONES: + return MediaRoute2Info.TYPE_WIRED_HEADPHONES; + case AudioDeviceInfo.TYPE_DOCK: + case AudioDeviceInfo.TYPE_DOCK_ANALOG: + return MediaRoute2Info.TYPE_DOCK; + case AudioDeviceInfo.TYPE_HDMI: + return MediaRoute2Info.TYPE_HDMI; + case AudioDeviceInfo.TYPE_USB_DEVICE: + return MediaRoute2Info.TYPE_USB_DEVICE; + case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: + return MediaRoute2Info.TYPE_BLUETOOTH_A2DP; + case AudioDeviceInfo.TYPE_BLE_HEADSET: + return MediaRoute2Info.TYPE_BLE_HEADSET; + case AudioDeviceInfo.TYPE_HEARING_AID: + return MediaRoute2Info.TYPE_HEARING_AID; + default: + return MediaRoute2Info.TYPE_UNKNOWN; + } + } + + + /* package */ static boolean isDeviceOutputAttributes( + @Nullable AudioDeviceAttributes audioDeviceAttributes) { + if (audioDeviceAttributes == null) { + return false; + } + + if (audioDeviceAttributes.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) { + return false; + } + + switch (audioDeviceAttributes.getType()) { + case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE: + case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: + case AudioDeviceInfo.TYPE_WIRED_HEADSET: + case AudioDeviceInfo.TYPE_WIRED_HEADPHONES: + case AudioDeviceInfo.TYPE_DOCK: + case AudioDeviceInfo.TYPE_DOCK_ANALOG: + case AudioDeviceInfo.TYPE_HDMI: + case AudioDeviceInfo.TYPE_USB_DEVICE: + return true; + default: + return false; + } + } + + /* package */ static boolean isBluetoothOutputAttributes( + @Nullable AudioDeviceAttributes audioDeviceAttributes) { + if (audioDeviceAttributes == null) { + return false; + } + + if (audioDeviceAttributes.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) { + return false; + } + + switch (audioDeviceAttributes.getType()) { + case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: + case AudioDeviceInfo.TYPE_BLE_HEADSET: + case AudioDeviceInfo.TYPE_BLE_SPEAKER: + case AudioDeviceInfo.TYPE_HEARING_AID: + return true; + default: + return false; + } + } + +} diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java new file mode 100644 index 000000000000..182aa6fcef02 --- /dev/null +++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java @@ -0,0 +1,240 @@ +/* + * 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.media; + +import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; +import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; +import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_DOCK; +import static android.media.MediaRoute2Info.TYPE_HDMI; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.media.AudioManager; +import android.media.AudioRoutesInfo; +import android.media.IAudioRoutesObserver; +import android.media.IAudioService; +import android.media.MediaRoute2Info; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; + + +/* package */ final class AudioPoliciesDeviceRouteController implements DeviceRouteController { + + private static final String TAG = "APDeviceRoutesController"; + + private static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE"; + + @NonNull + private final Context mContext; + @NonNull + private final AudioManager mAudioManager; + @NonNull + private final IAudioService mAudioService; + + @NonNull + private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; + @NonNull + private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver(); + + private int mDeviceVolume; + + @NonNull + private MediaRoute2Info mDeviceRoute; + @Nullable + private MediaRoute2Info mSelectedRoute; + + @VisibleForTesting + /* package */ AudioPoliciesDeviceRouteController(@NonNull Context context, + @NonNull AudioManager audioManager, + @NonNull IAudioService audioService, + @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { + Objects.requireNonNull(context); + Objects.requireNonNull(audioManager); + Objects.requireNonNull(audioService); + Objects.requireNonNull(onDeviceRouteChangedListener); + + mContext = context; + mOnDeviceRouteChangedListener = onDeviceRouteChangedListener; + + mAudioManager = audioManager; + mAudioService = audioService; + + AudioRoutesInfo newAudioRoutes = null; + try { + newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); + } catch (RemoteException e) { + Slog.w(TAG, "Cannot connect to audio service to start listen to routes", e); + } + + mDeviceRoute = createRouteFromAudioInfo(newAudioRoutes); + } + + @Override + public synchronized boolean selectRoute(@Nullable Integer type) { + if (type == null) { + mSelectedRoute = null; + return true; + } + + if (!isDeviceRouteType(type)) { + return false; + } + + mSelectedRoute = createRouteFromAudioInfo(type); + return true; + } + + @Override + @NonNull + public synchronized MediaRoute2Info getDeviceRoute() { + if (mSelectedRoute != null) { + return mSelectedRoute; + } + return mDeviceRoute; + } + + @Override + public synchronized boolean updateVolume(int volume) { + if (mDeviceVolume == volume) { + return false; + } + + mDeviceVolume = volume; + + if (mSelectedRoute != null) { + mSelectedRoute = new MediaRoute2Info.Builder(mSelectedRoute) + .setVolume(volume) + .build(); + } + + mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) + .setVolume(volume) + .build(); + + return true; + } + + @NonNull + private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) { + int type = TYPE_BUILTIN_SPEAKER; + + if (newRoutes != null) { + if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) { + type = TYPE_WIRED_HEADPHONES; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { + type = TYPE_WIRED_HEADSET; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { + type = TYPE_DOCK; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) { + type = TYPE_HDMI; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { + type = TYPE_USB_DEVICE; + } + } + + return createRouteFromAudioInfo(type); + } + + @NonNull + private MediaRoute2Info createRouteFromAudioInfo(@MediaRoute2Info.Type int type) { + int name = R.string.default_audio_route_name; + + switch (type) { + case TYPE_WIRED_HEADPHONES: + case TYPE_WIRED_HEADSET: + name = R.string.default_audio_route_name_headphones; + break; + case TYPE_DOCK: + name = R.string.default_audio_route_name_dock_speakers; + break; + case TYPE_HDMI: + name = R.string.default_audio_route_name_external_device; + break; + case TYPE_USB_DEVICE: + name = R.string.default_audio_route_name_usb; + break; + } + + synchronized (this) { + return new MediaRoute2Info.Builder( + DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString()) + .setVolumeHandling(mAudioManager.isVolumeFixed() + ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED + : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolume(mDeviceVolume) + .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) + .setType(type) + .addFeature(FEATURE_LIVE_AUDIO) + .addFeature(FEATURE_LIVE_VIDEO) + .addFeature(FEATURE_LOCAL_PLAYBACK) + .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) + .build(); + } + } + + /** + * Checks if the given type is a device route. + * + * <p>Device route means a route which is either built-in or wired to the current device. + * + * @param type specifies the type of the device. + * @return {@code true} if the device is wired or built-in and {@code false} otherwise. + */ + private boolean isDeviceRouteType(@MediaRoute2Info.Type int type) { + switch (type) { + case TYPE_BUILTIN_SPEAKER: + case TYPE_WIRED_HEADPHONES: + case TYPE_WIRED_HEADSET: + case TYPE_DOCK: + case TYPE_HDMI: + case TYPE_USB_DEVICE: + return true; + default: + return false; + } + } + + private class AudioRoutesObserver extends IAudioRoutesObserver.Stub { + + @Override + public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) { + boolean isDeviceRouteChanged; + MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes); + + synchronized (AudioPoliciesDeviceRouteController.this) { + mDeviceRoute = deviceRoute; + isDeviceRouteChanged = mSelectedRoute == null; + } + + if (isDeviceRouteChanged) { + mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); + } + } + } + +} diff --git a/services/core/java/com/android/server/media/BluetoothRouteController.java b/services/core/java/com/android/server/media/BluetoothRouteController.java index d4a118458952..66985e0b2533 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteController.java +++ b/services/core/java/com/android/server/media/BluetoothRouteController.java @@ -53,7 +53,16 @@ import java.util.Objects; return new NoOpBluetoothRouteController(); } - return new LegacyBluetoothRouteController(context, btAdapter, listener); + MediaFeatureFlagManager flagManager = MediaFeatureFlagManager.getInstance(); + boolean isUsingLegacyController = flagManager.getBoolean( + MediaFeatureFlagManager.FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER, + true); + + if (isUsingLegacyController) { + return new LegacyBluetoothRouteController(context, btAdapter, listener); + } else { + return new AudioPoliciesBluetoothRouteController(context, btAdapter, listener); + } } /** diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java index 8bd6416a6ddb..3875c84e618b 100644 --- a/services/core/java/com/android/server/media/DeviceRouteController.java +++ b/services/core/java/com/android/server/media/DeviceRouteController.java @@ -16,32 +16,14 @@ package com.android.server.media; -import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; -import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; -import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK; -import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; -import static android.media.MediaRoute2Info.TYPE_DOCK; -import static android.media.MediaRoute2Info.TYPE_HDMI; -import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; -import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; -import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.media.AudioManager; -import android.media.AudioRoutesInfo; import android.media.IAudioRoutesObserver; import android.media.IAudioService; import android.media.MediaRoute2Info; -import android.os.RemoteException; import android.os.ServiceManager; -import android.util.Slog; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Objects; /** * Controls device routes. @@ -49,145 +31,77 @@ import java.util.Objects; * <p>A device route is a system wired route, for example, built-in speaker, wired * headsets and headphones, dock, hdmi, or usb devices. * - * <p>Thread safe. - * * @see SystemMediaRoute2Provider */ -/* package */ final class DeviceRouteController { - - private static final String TAG = "WiredRoutesController"; - - private static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE"; - - @NonNull - private final Context mContext; - @NonNull - private final AudioManager mAudioManager; - @NonNull - private final IAudioService mAudioService; - - @NonNull - private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; - @NonNull - private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver(); - - private int mDeviceVolume; - private MediaRoute2Info mDeviceRoute; +/* package */ interface DeviceRouteController { + /** + * Returns a new instance of {@link DeviceRouteController}. + */ /* package */ static DeviceRouteController createInstance(@NonNull Context context, @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { AudioManager audioManager = context.getSystemService(AudioManager.class); IAudioService audioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); - return new DeviceRouteController(context, - audioManager, - audioService, - onDeviceRouteChangedListener); - } - - @VisibleForTesting - /* package */ DeviceRouteController(@NonNull Context context, - @NonNull AudioManager audioManager, - @NonNull IAudioService audioService, - @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { - Objects.requireNonNull(context); - Objects.requireNonNull(audioManager); - Objects.requireNonNull(audioService); - Objects.requireNonNull(onDeviceRouteChangedListener); - - mContext = context; - mOnDeviceRouteChangedListener = onDeviceRouteChangedListener; - - mAudioManager = audioManager; - mAudioService = audioService; - - AudioRoutesInfo newAudioRoutes = null; - try { - newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); - } catch (RemoteException e) { - Slog.w(TAG, "Cannot connect to audio service to start listen to routes", e); + MediaFeatureFlagManager flagManager = MediaFeatureFlagManager.getInstance(); + boolean isUsingLegacyController = flagManager.getBoolean( + MediaFeatureFlagManager.FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER, + true); + + if (isUsingLegacyController) { + return new LegacyDeviceRouteController(context, + audioManager, + audioService, + onDeviceRouteChangedListener); + } else { + return new AudioPoliciesDeviceRouteController(context, + audioManager, + audioService, + onDeviceRouteChangedListener); } - - mDeviceRoute = createRouteFromAudioInfo(newAudioRoutes); } + /** + * Select the route with the given built-in or wired {@link MediaRoute2Info.Type}. + * + * <p>If the type is {@code null} then unselects the route and falls back to the default device + * route observed from + * {@link com.android.server.audio.AudioService#startWatchingRoutes(IAudioRoutesObserver)}. + * + * @param type device type. May be {@code null} to unselect currently selected route. + * @return whether the selection succeeds. If the selection fails the state of the controller + * remains intact. + */ + boolean selectRoute(@Nullable @MediaRoute2Info.Type Integer type); + + /** + * Returns currently selected device (built-in or wired) route. + * + * @return non-null device route. + */ @NonNull - /* package */ synchronized MediaRoute2Info getDeviceRoute() { - return mDeviceRoute; - } - - /* package */ synchronized boolean updateVolume(int volume) { - if (mDeviceVolume == volume) { - return false; - } - - mDeviceVolume = volume; - mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) - .setVolume(volume) - .build(); - - return true; - } - - private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) { - int name = R.string.default_audio_route_name; - int type = TYPE_BUILTIN_SPEAKER; - - if (newRoutes != null) { - if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) { - type = TYPE_WIRED_HEADPHONES; - name = com.android.internal.R.string.default_audio_route_name_headphones; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { - type = TYPE_WIRED_HEADSET; - name = com.android.internal.R.string.default_audio_route_name_headphones; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { - type = TYPE_DOCK; - name = com.android.internal.R.string.default_audio_route_name_dock_speakers; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) { - type = TYPE_HDMI; - name = com.android.internal.R.string.default_audio_route_name_external_device; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { - type = TYPE_USB_DEVICE; - name = com.android.internal.R.string.default_audio_route_name_usb; - } - } - - synchronized (this) { - return new MediaRoute2Info.Builder( - DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString()) - .setVolumeHandling(mAudioManager.isVolumeFixed() - ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED - : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) - .setVolume(mDeviceVolume) - .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) - .setType(type) - .addFeature(FEATURE_LIVE_AUDIO) - .addFeature(FEATURE_LIVE_VIDEO) - .addFeature(FEATURE_LOCAL_PLAYBACK) - .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) - .build(); - } - } - - private void notifyDeviceRouteUpdate(@NonNull MediaRoute2Info deviceRoute) { - mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); - } - - /* package */ interface OnDeviceRouteChangedListener { + MediaRoute2Info getDeviceRoute(); + + /** + * Updates device route volume. + * + * @param volume specifies a volume for the device route or 0 for unknown. + * @return {@code true} if updated successfully and {@code false} otherwise. + */ + boolean updateVolume(int volume); + + /** + * Interface for receiving events when device route has changed. + */ + interface OnDeviceRouteChangedListener { + + /** + * Called when device route has changed. + * + * @param deviceRoute non-null device route. + */ void onDeviceRouteChanged(@NonNull MediaRoute2Info deviceRoute); } - private class AudioRoutesObserver extends IAudioRoutesObserver.Stub { - - @Override - public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) { - MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes); - synchronized (DeviceRouteController.this) { - mDeviceRoute = deviceRoute; - } - notifyDeviceRouteUpdate(deviceRoute); - } - } - } diff --git a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java new file mode 100644 index 000000000000..971d11f24b9c --- /dev/null +++ b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java @@ -0,0 +1,184 @@ +/* + * 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.media; + +import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; +import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; +import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_DOCK; +import static android.media.MediaRoute2Info.TYPE_HDMI; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.media.AudioManager; +import android.media.AudioRoutesInfo; +import android.media.IAudioRoutesObserver; +import android.media.IAudioService; +import android.media.MediaRoute2Info; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; + +/** + * Controls device routes. + * + * <p>A device route is a system wired route, for example, built-in speaker, wired + * headsets and headphones, dock, hdmi, or usb devices. + * + * <p>Thread safe. + * + * @see SystemMediaRoute2Provider + */ +/* package */ final class LegacyDeviceRouteController implements DeviceRouteController { + + private static final String TAG = "LDeviceRouteController"; + + private static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE"; + + @NonNull + private final Context mContext; + @NonNull + private final AudioManager mAudioManager; + @NonNull + private final IAudioService mAudioService; + + @NonNull + private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; + @NonNull + private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver(); + + private int mDeviceVolume; + private MediaRoute2Info mDeviceRoute; + + @VisibleForTesting + /* package */ LegacyDeviceRouteController(@NonNull Context context, + @NonNull AudioManager audioManager, + @NonNull IAudioService audioService, + @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { + Objects.requireNonNull(context); + Objects.requireNonNull(audioManager); + Objects.requireNonNull(audioService); + Objects.requireNonNull(onDeviceRouteChangedListener); + + mContext = context; + mOnDeviceRouteChangedListener = onDeviceRouteChangedListener; + + mAudioManager = audioManager; + mAudioService = audioService; + + AudioRoutesInfo newAudioRoutes = null; + try { + newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); + } catch (RemoteException e) { + Slog.w(TAG, "Cannot connect to audio service to start listen to routes", e); + } + + mDeviceRoute = createRouteFromAudioInfo(newAudioRoutes); + } + + @Override + public boolean selectRoute(@Nullable Integer type) { + // No-op as the controller does not support selection from the outside of the class. + return false; + } + + @Override + @NonNull + public synchronized MediaRoute2Info getDeviceRoute() { + return mDeviceRoute; + } + + @Override + public synchronized boolean updateVolume(int volume) { + if (mDeviceVolume == volume) { + return false; + } + + mDeviceVolume = volume; + mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) + .setVolume(volume) + .build(); + + return true; + } + + private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) { + int name = R.string.default_audio_route_name; + int type = TYPE_BUILTIN_SPEAKER; + + if (newRoutes != null) { + if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) { + type = TYPE_WIRED_HEADPHONES; + name = com.android.internal.R.string.default_audio_route_name_headphones; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { + type = TYPE_WIRED_HEADSET; + name = com.android.internal.R.string.default_audio_route_name_headphones; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { + type = TYPE_DOCK; + name = com.android.internal.R.string.default_audio_route_name_dock_speakers; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) { + type = TYPE_HDMI; + name = com.android.internal.R.string.default_audio_route_name_external_device; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { + type = TYPE_USB_DEVICE; + name = com.android.internal.R.string.default_audio_route_name_usb; + } + } + + synchronized (this) { + return new MediaRoute2Info.Builder( + DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString()) + .setVolumeHandling(mAudioManager.isVolumeFixed() + ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED + : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolume(mDeviceVolume) + .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) + .setType(type) + .addFeature(FEATURE_LIVE_AUDIO) + .addFeature(FEATURE_LIVE_VIDEO) + .addFeature(FEATURE_LOCAL_PLAYBACK) + .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) + .build(); + } + } + + private void notifyDeviceRouteUpdate(@NonNull MediaRoute2Info deviceRoute) { + mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); + } + + private class AudioRoutesObserver extends IAudioRoutesObserver.Stub { + + @Override + public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) { + MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes); + synchronized (LegacyDeviceRouteController.this) { + mDeviceRoute = deviceRoute; + } + notifyDeviceRouteUpdate(deviceRoute); + } + } + +} diff --git a/services/core/java/com/android/server/media/MediaFeatureFlagManager.java b/services/core/java/com/android/server/media/MediaFeatureFlagManager.java index 723cda056694..70ee38f8f7b0 100644 --- a/services/core/java/com/android/server/media/MediaFeatureFlagManager.java +++ b/services/core/java/com/android/server/media/MediaFeatureFlagManager.java @@ -32,7 +32,7 @@ import java.lang.annotation.Target; private static final String NAMESPACE_MEDIA_BETTER_TOGETHER = "media_better_together"; @StringDef(prefix = "FEATURE_", value = { - FEATURE_IS_USING_LEGACY_BLUETOOTH_CONTROLLER + FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER }) @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) @Retention(RetentionPolicy.SOURCE) @@ -43,7 +43,7 @@ import java.lang.annotation.Target; * 'Audio Strategies'-aware controller. */ /* package */ static final @MediaFeatureFlag String - FEATURE_IS_USING_LEGACY_BLUETOOTH_CONTROLLER = + FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER = "BluetoothRouteController__enable_legacy_bluetooth_routes_controller"; private static final MediaFeatureFlagManager sInstance = new MediaFeatureFlagManager(); @@ -52,7 +52,7 @@ import java.lang.annotation.Target; // Empty to prevent instantiation. } - /* package */ MediaFeatureFlagManager getInstance() { + /* package */ static MediaFeatureFlagManager getInstance() { return sInstance; } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 638e81a5df36..5d5c621eb3f5 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -16,11 +16,14 @@ package com.android.server.media; +import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.media.AudioAttributes; +import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; @@ -37,6 +40,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import java.util.List; import java.util.Objects; /** @@ -60,7 +64,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { private final UserHandle mUser; private final DeviceRouteController mDeviceRouteController; - private final BluetoothRouteController mBtRouteProvider; + private final BluetoothRouteController mBluetoothRouteController; private String mSelectedRouteId; // For apps without MODIFYING_AUDIO_ROUTING permission. @@ -71,6 +75,26 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { private final AudioManagerBroadcastReceiver mAudioReceiver = new AudioManagerBroadcastReceiver(); + private final AudioManager.OnDevicesForAttributesChangedListener + mOnDevicesForAttributesChangedListener = + new AudioManager.OnDevicesForAttributesChangedListener() { + @Override + public void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes, + @NonNull List<AudioDeviceAttributes> devices) { + if (attributes.getUsage() != AudioAttributes.USAGE_MEDIA) { + return; + } + + mHandler.post(() -> { + updateSelectedAudioDevice(devices); + notifyProviderState(); + if (updateSessionInfosIfNeeded()) { + notifySessionInfoUpdated(); + } + }); + } + }; + private final Object mRequestLock = new Object(); @GuardedBy("mRequestLock") private volatile SessionCreationRequest mPendingSessionCreationRequest; @@ -84,7 +108,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - mBtRouteProvider = BluetoothRouteController.createInstance(context, (routes) -> { + mBluetoothRouteController = BluetoothRouteController.createInstance(context, (routes) -> { publishProviderState(); if (updateSessionInfosIfNeeded()) { notifySessionInfoUpdated(); @@ -100,8 +124,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { }); }); + mAudioManager.addOnDevicesForAttributesChangedListener( + AudioAttributesUtils.ATTRIBUTES_MEDIA, mContext.getMainExecutor(), + mOnDevicesForAttributesChangedListener); + // These methods below should be called after all fields are initialized, as they // access the fields inside. + List<AudioDeviceAttributes> devices = + mAudioManager.getDevicesForAttributes(AudioAttributesUtils.ATTRIBUTES_MEDIA); + updateSelectedAudioDevice(devices); updateProviderState(); updateSessionInfosIfNeeded(); } @@ -113,7 +144,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { intentFilter, null, null); mHandler.post(() -> { - mBtRouteProvider.start(mUser); + mBluetoothRouteController.start(mUser); notifyProviderState(); }); updateVolume(); @@ -122,7 +153,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { public void stop() { mContext.unregisterReceiver(mAudioReceiver); mHandler.post(() -> { - mBtRouteProvider.stop(); + mBluetoothRouteController.stop(); notifyProviderState(); }); } @@ -189,9 +220,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute(); if (TextUtils.equals(routeId, deviceRoute.getId())) { - mBtRouteProvider.transferTo(null); + mBluetoothRouteController.transferTo(null); } else { - mBtRouteProvider.transferTo(routeId); + mBluetoothRouteController.transferTo(routeId); } } @@ -232,20 +263,40 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( SYSTEM_SESSION_ID, packageName).setSystemSession(true); builder.addSelectedRoute(deviceRoute.getId()); - for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) { + for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) { builder.addTransferableRoute(route.getId()); } return builder.setProviderId(mUniqueId).build(); } } + private void updateSelectedAudioDevice(@NonNull List<AudioDeviceAttributes> devices) { + if (devices.isEmpty()) { + Slog.w(TAG, "The list of preferred devices was empty."); + return; + } + + AudioDeviceAttributes audioDeviceAttributes = devices.get(0); + + if (AudioAttributesUtils.isDeviceOutputAttributes(audioDeviceAttributes)) { + mDeviceRouteController.selectRoute( + AudioAttributesUtils.mapToMediaRouteType(audioDeviceAttributes)); + mBluetoothRouteController.selectRoute(null); + } else if (AudioAttributesUtils.isBluetoothOutputAttributes(audioDeviceAttributes)) { + mDeviceRouteController.selectRoute(null); + mBluetoothRouteController.selectRoute(audioDeviceAttributes.getAddress()); + } else { + Slog.w(TAG, "Unknown audio attributes: " + audioDeviceAttributes); + } + } + private void updateProviderState() { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); // We must have a device route in the provider info. builder.addRoute(mDeviceRouteController.getDeviceRoute()); - for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) { + for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) { builder.addRoute(route); } MediaRoute2ProviderInfo providerInfo = builder.build(); @@ -269,7 +320,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute(); MediaRoute2Info selectedRoute = deviceRoute; - MediaRoute2Info selectedBtRoute = mBtRouteProvider.getSelectedRoute(); + MediaRoute2Info selectedBtRoute = mBluetoothRouteController.getSelectedRoute(); if (selectedBtRoute != null) { selectedRoute = selectedBtRoute; builder.addTransferableRoute(deviceRoute.getId()); @@ -281,7 +332,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { .build(); builder.addSelectedRoute(mSelectedRouteId); - for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) { + for (MediaRoute2Info route : mBluetoothRouteController.getTransferableRoutes()) { builder.addTransferableRoute(route.getId()); } @@ -361,7 +412,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { .build(); } - if (mBtRouteProvider.updateVolumeForDevices(devices, volume)) { + if (mBluetoothRouteController.updateVolumeForDevices(devices, volume)) { return; } diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 53e841d50b33..73440b7f2eec 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -892,6 +892,7 @@ abstract public class ManagedServices { return allowedComponents; } + @NonNull protected List<String> getAllowedPackages(int userId) { final List<String> allowedPackages = new ArrayList<>(); synchronized (mApproved) { @@ -1181,25 +1182,6 @@ abstract public class ManagedServices { return installed; } - protected Set<String> getAllowedPackages() { - final Set<String> allowedPackages = new ArraySet<>(); - synchronized (mApproved) { - for (int k = 0; k < mApproved.size(); k++) { - ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k); - for (int i = 0; i < allowedByType.size(); i++) { - final ArraySet<String> allowed = allowedByType.valueAt(i); - for (int j = 0; j < allowed.size(); j++) { - String pkgName = getPackageName(allowed.valueAt(j)); - if (!TextUtils.isEmpty(pkgName)) { - allowedPackages.add(pkgName); - } - } - } - } - } - return allowedPackages; - } - private void trimApprovedListsAccordingToInstalledServices(int userId) { synchronized (mApproved) { final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0d394570ab8e..53b03d58beae 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2709,16 +2709,18 @@ public class NotificationManagerService extends SystemService { } private void sendRegisteredOnlyBroadcast(String action) { - Intent intent = new Intent(action); - getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), - UserHandle.ALL, null); + int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true); + Intent intent = new Intent(action).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + for (int userId : userIds) { + getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null); + } // explicitly send the broadcast to all DND packages, even if they aren't currently running - intent.setFlags(0); - final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages(); - for (String pkg : dndApprovedPackages) { - intent.setPackage(pkg); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - getContext().sendBroadcastAsUser(intent, UserHandle.ALL); + for (int userId : userIds) { + for (String pkg : mConditionProviders.getAllowedPackages(userId)) { + Intent pkgIntent = new Intent(action).setPackage(pkg).setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId)); + } } } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index c63cdddc8560..59af58fb0dfb 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -862,11 +862,11 @@ public class PreferencesHelper implements RankingConfig { if (r == null) { throw new IllegalArgumentException("Invalid package"); } + if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) { + throw new IllegalStateException("Limit exceed; cannot create more groups"); + } if (fromTargetApp) { group.setBlocked(false); - if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) { - throw new IllegalStateException("Limit exceed; cannot create more groups"); - } } final NotificationChannelGroup oldGroup = r.groups.get(group.getId()); if (oldGroup != null) { diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index a868470b0042..7fe6c7d5aa93 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -164,6 +164,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.LocalManagerRegistry; import com.android.server.art.model.DexoptParams; +import com.android.server.art.model.DexoptResult; import com.android.server.pm.Installer.LegacyDexoptDisabledException; import com.android.server.pm.dex.ArtManagerService; import com.android.server.pm.dex.DexManager; @@ -2534,8 +2535,9 @@ final class InstallPackageHelper { packageManagerLocal.withFilteredSnapshot()) { DexoptParams params = dexoptOptions.convertToDexoptParams(0 /* extraFlags */); - DexOptHelper.getArtManagerLocal().dexoptPackage( + DexoptResult dexOptResult = DexOptHelper.getArtManagerLocal().dexoptPackage( snapshot, packageName, params); + installRequest.onDexoptFinished(dexOptResult); } } else { try { diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index 46ea010d9aaa..95e790450724 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -43,6 +43,7 @@ import android.util.ArrayMap; import android.util.ExceptionUtils; import android.util.Slog; +import com.android.server.art.model.DexoptResult; import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; @@ -127,6 +128,8 @@ final class InstallRequest { private final int mSessionId; private final int mRequireUserAction; + private int mDexoptStatus; + // New install InstallRequest(InstallingSession params) { mUserId = params.getUser().getIdentifier(); @@ -609,6 +612,10 @@ final class InstallRequest { return mRequireUserAction; } + public int getDexoptStatus() { + return mDexoptStatus; + } + public void setScanFlags(int scanFlags) { mScanFlags = scanFlags; } @@ -799,6 +806,25 @@ final class InstallRequest { } } + public void onDexoptFinished(DexoptResult dexoptResult) { + if (mPackageMetrics == null) { + return; + } + mDexoptStatus = dexoptResult.getFinalStatus(); + if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) { + return; + } + long durationMillis = 0; + for (DexoptResult.PackageDexoptResult packageResult : + dexoptResult.getPackageDexoptResults()) { + for (DexoptResult.DexContainerFileDexoptResult fileResult : + packageResult.getDexContainerFileDexoptResults()) { + durationMillis += fileResult.getDex2oatWallTimeMillis(); + } + } + mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis); + } + public void onInstallCompleted() { if (getReturnCode() == INSTALL_SUCCEEDED) { if (mPackageMetrics != null) { diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 9329f063aee5..0d417e457509 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -136,9 +136,7 @@ public class Installer extends SystemService { } /** - * @param isolated indicates if this object should <em>not</em> connect to - * the real {@code installd}. All remote calls will be ignored - * unless you extend this class and intercept them. + * @param isolated Make the installer isolated. See {@link isIsolated}. */ public Installer(Context context, boolean isolated) { super(context); @@ -153,6 +151,15 @@ public class Installer extends SystemService { mWarnIfHeld = warnIfHeld; } + /** + * Returns true if the installer is isolated, i.e. if this object should <em>not</em> connect to + * the real {@code installd}. All remote calls will be ignored unless you extend this class and + * intercept them. + */ + public boolean isIsolated() { + return mIsolated; + } + @Override public void onStart() { if (mIsolated) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 767c0a73bc54..6a2ddc8f94b0 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static com.android.server.pm.DexOptHelper.useArtService; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; @@ -301,6 +302,15 @@ public class OtaDexoptService extends IOtaDexopt.Stub { throws InstallerException { final StringBuilder builder = new StringBuilder(); + if (useArtService()) { + if ((dexFlags & DEXOPT_SECONDARY_DEX) != 0) { + // installd may change the reference profile in place for secondary dex + // files, which isn't safe with the lock free approach in ART Service. + throw new IllegalArgumentException( + "Invalid OTA dexopt call for secondary dex"); + } + } + // The current version. For v10, see b/115993344. builder.append("10 "); @@ -353,7 +363,6 @@ public class OtaDexoptService extends IOtaDexopt.Stub { PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer( collectingInstaller, mPackageManagerService.mInstallLock, mContext); - // TODO(b/251903639): Allow this use of legacy dexopt code even when ART Service is enabled. try { optimizer.performDexOpt(pkg, pkgSetting, null /* ISAs */, null /* CompilerStats.PackageStats */, @@ -362,9 +371,19 @@ public class OtaDexoptService extends IOtaDexopt.Stub { new DexoptOptions(pkg.getPackageName(), compilationReason, DexoptOptions.DEXOPT_BOOT_COMPLETE)); } catch (LegacyDexoptDisabledException e) { - throw new RuntimeException(e); + // OTA is still allowed to use the legacy dexopt code even when ART Service is enabled. + // The installer is isolated and won't call into installd, and the dexopt() method is + // overridden to only collect the command above. Hence we shouldn't go into any code + // path where this exception is thrown. + Slog.wtf(TAG, e); } + // ART Service compat note: These commands are consumed by the otapreopt binary, which uses + // the same legacy dexopt code as installd to invoke dex2oat. It provides output path + // implementations (see calculate_odex_file_path and create_cache_path in + // frameworks/native/cmds/installd/otapreopt.cpp) to write to different odex files than + // those used by ART Service in its ordinary operations, so it doesn't interfere with ART + // Service even when dalvik.vm.useartservice is true. return commands; } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 0a90e7a30db6..8a4080ff029d 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -18,6 +18,7 @@ package com.android.server.pm; import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; +import static com.android.server.pm.DexOptHelper.useArtService; import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS; @@ -329,8 +330,22 @@ public class PackageDexOptimizer { String profileName = ArtManager.getProfileName( i == 0 ? null : pkg.getSplitNames()[i - 1]); - final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() - || packageUseInfo.isUsedByOtherApps(path); + + final boolean isUsedByOtherApps; + if (options.isDexoptAsSharedLibrary()) { + isUsedByOtherApps = true; + } else if (useArtService()) { + // We get here when collecting dexopt commands in OTA preopt, even when ART Service + // is in use. packageUseInfo isn't useful in that case since the legacy dex use + // database hasn't been updated. So we'd have to query ART Service instead, but it + // doesn't provide that API. Just cop-out and bypass the cloud profile handling. + // That means such apps will get preopted wrong, and we'll leave it to a later + // background dexopt after reboot instead. + isUsedByOtherApps = false; + } else { + isUsedByOtherApps = packageUseInfo.isUsedByOtherApps(path); + } + String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter()); // If the app is used by other apps, we must not use the existing profile because it // may contain user data, unless the profile is newly created on install. @@ -446,6 +461,14 @@ public class PackageDexOptimizer { private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path, @Nullable String dexMetadataPath) throws LegacyDexoptDisabledException { if (dexMetadataPath != null) { + if (mInstaller.isIsolated()) { + // If the installer is isolated, the two calls to it below will return immediately, + // so this only short-circuits that a bit. We need to do it to avoid the + // LegacyDexoptDisabledException getting thrown first, when we get here during OTA + // preopt and ART Service is enabled. + return true; + } + try { // Make sure we don't keep any existing contents. mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName); @@ -879,7 +902,12 @@ public class PackageDexOptimizer { private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter, String classLoaderContext, int profileAnalysisResult, boolean downgrade, int dexoptFlags, String oatDir) throws LegacyDexoptDisabledException { - Installer.checkLegacyDexoptDisabled(); + // Allow calls from OtaDexoptService even when ART Service is in use. The installer is + // isolated in that case so later calls to it won't call into installd anyway. + if (!mInstaller.isIsolated()) { + Installer.checkLegacyDexoptDisabled(); + } + final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0; final boolean isProfileGuidedFilter = (dexoptFlags & DEXOPT_PROFILE_GUIDED) != 0; boolean newProfile = profileAnalysisResult == PROFILE_ANALYSIS_OPTIMIZE; @@ -948,6 +976,8 @@ public class PackageDexOptimizer { */ private int analyseProfiles(AndroidPackage pkg, int uid, String profileName, String compilerFilter) throws LegacyDexoptDisabledException { + Installer.checkLegacyDexoptDisabled(); + // Check if we are allowed to merge and if the compiler filter is profile guided. if (!isProfileGuidedCompilerFilter(compilerFilter)) { return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 928ffa718c6f..3f9a0bc89641 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -24,6 +24,7 @@ import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDWR; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; import static com.android.server.LocalManagerRegistry.ManagerNotFoundException; import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION; import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; @@ -94,6 +95,7 @@ import com.android.server.EventLogTags; import com.android.server.IntentResolver; import com.android.server.LocalManagerRegistry; import com.android.server.Watchdog; +import com.android.server.am.ActivityManagerUtils; import com.android.server.compat.PlatformCompat; import com.android.server.pm.dex.PackageDexUsage; import com.android.server.pm.pkg.AndroidPackage; @@ -1186,12 +1188,6 @@ public class PackageManagerServiceUtils { continue; } - // Only enforce filter matching if target app's target SDK >= T - if (!compat.isChangeEnabledInternal( - ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo)) { - continue; - } - final ParsedMainComponent comp; if (info instanceof ActivityInfo) { if (isReceiver) { @@ -1210,6 +1206,10 @@ public class PackageManagerServiceUtils { continue; } + // Only enforce filter matching if target app's target SDK >= T + final boolean enforce = compat.isChangeEnabledInternal( + ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo); + boolean match = false; for (int j = 0, size = comp.getIntents().size(); j < size; ++j) { IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter(); @@ -1219,14 +1219,19 @@ public class PackageManagerServiceUtils { } } if (!match) { - Slog.w(TAG, "Intent does not match component's intent filter: " + intent); - Slog.w(TAG, "Access blocked: " + comp.getComponentName()); - if (DEBUG_INTENT_MATCHING) { - Slog.v(TAG, "Component intent filters:"); - comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, " ")); - Slog.v(TAG, "-----------------------------"); + ActivityManagerUtils.logUnsafeIntentEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH, + filterCallingUid, intent, resolvedType, enforce); + if (enforce) { + Slog.w(TAG, "Intent does not match component's intent filter: " + intent); + Slog.w(TAG, "Access blocked: " + comp.getComponentName()); + if (DEBUG_INTENT_MATCHING) { + Slog.v(TAG, "Component intent filters:"); + comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, " ")); + Slog.v(TAG, "-----------------------------"); + } + resolveInfos.remove(i); } - resolveInfos.remove(i); } } } diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java index fe014a499073..80d6ebbd90b3 100644 --- a/services/core/java/com/android/server/pm/PackageMetrics.java +++ b/services/core/java/com/android/server/pm/PackageMetrics.java @@ -48,12 +48,14 @@ final class PackageMetrics { public static final int STEP_SCAN = 2; public static final int STEP_RECONCILE = 3; public static final int STEP_COMMIT = 4; + public static final int STEP_DEXOPT = 5; @IntDef(prefix = {"STEP_"}, value = { STEP_PREPARE, STEP_SCAN, STEP_RECONCILE, STEP_COMMIT, + STEP_DEXOPT }) @Retention(RetentionPolicy.SOURCE) public @interface StepInt { @@ -175,6 +177,10 @@ final class PackageMetrics { } } + public void onStepFinished(@StepInt int step, long durationMillis) { + mInstallSteps.put(step, new InstallStep(durationMillis)); + } + // List of steps (e.g., 1, 2, 3) and corresponding list of durations (e.g., 200ms, 100ms, 150ms) private Pair<int[], long[]> getInstallStepDurations() { ArrayList<Integer> steps = new ArrayList<>(); @@ -203,6 +209,11 @@ final class PackageMetrics { mStartTimestampMillis = System.currentTimeMillis(); } + InstallStep(long durationMillis) { + mStartTimestampMillis = -1; + mDurationMillis = durationMillis; + } + void finish() { mDurationMillis = System.currentTimeMillis() - mStartTimestampMillis; } diff --git a/services/core/java/com/android/server/pm/ResilientAtomicFile.java b/services/core/java/com/android/server/pm/ResilientAtomicFile.java new file mode 100644 index 000000000000..19aa4f8e8d0b --- /dev/null +++ b/services/core/java/com/android/server/pm/ResilientAtomicFile.java @@ -0,0 +1,265 @@ +/* + * 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.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.util.Log; +import android.util.Slog; + +import com.android.server.security.FileIntegrity; + +import libcore.io.IoUtils; + +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +final class ResilientAtomicFile implements Closeable { + private static final String LOG_TAG = "ResilientAtomicFile"; + + private final File mFile; + + private final File mTemporaryBackup; + + private final File mReserveCopy; + + private final int mFileMode; + + private final String mDebugName; + + private final ReadEventLogger mReadEventLogger; + + // Write state. + private FileOutputStream mMainOutStream = null; + private FileInputStream mMainInStream = null; + private FileOutputStream mReserveOutStream = null; + private FileInputStream mReserveInStream = null; + + // Read state. + private File mCurrentFile = null; + private FileInputStream mCurrentInStream = null; + + private void finalizeOutStream(FileOutputStream str) throws IOException { + // Flash/sync + set permissions. + str.flush(); + FileUtils.sync(str); + FileUtils.setPermissions(str.getFD(), mFileMode, -1, -1); + } + + ResilientAtomicFile(@NonNull File file, @NonNull File temporaryBackup, + @NonNull File reserveCopy, int fileMode, String debugName, + @Nullable ReadEventLogger readEventLogger) { + mFile = file; + mTemporaryBackup = temporaryBackup; + mReserveCopy = reserveCopy; + mFileMode = fileMode; + mDebugName = debugName; + mReadEventLogger = readEventLogger; + } + + public File getBaseFile() { + return mFile; + } + + public FileOutputStream startWrite() throws IOException { + if (mMainOutStream != null) { + throw new IllegalStateException("Duplicate startWrite call?"); + } + + new File(mFile.getParent()).mkdirs(); + + if (mFile.exists()) { + // Presence of backup settings file indicates that we failed + // to persist packages earlier. So preserve the older + // backup for future reference since the current packages + // might have been corrupted. + if (!mTemporaryBackup.exists()) { + if (!mFile.renameTo(mTemporaryBackup)) { + throw new IOException("Unable to backup " + mDebugName + + " file, current changes will be lost at reboot"); + } + } else { + mFile.delete(); + Slog.w(LOG_TAG, "Preserving older " + mDebugName + " backup"); + } + } + // Reserve copy is not valid anymore. + mReserveCopy.delete(); + + // In case of MT access, it's possible the files get overwritten during write. + // Let's open all FDs we need now. + mMainOutStream = new FileOutputStream(mFile); + mMainInStream = new FileInputStream(mFile); + mReserveOutStream = new FileOutputStream(mReserveCopy); + mReserveInStream = new FileInputStream(mReserveCopy); + + return mMainOutStream; + } + + public void finishWrite(FileOutputStream str) throws IOException { + if (mMainOutStream != str) { + throw new IllegalStateException("Invalid incoming stream."); + } + + // Flush and set permissions. + try (FileOutputStream mainOutStream = mMainOutStream) { + mMainOutStream = null; + finalizeOutStream(mainOutStream); + } + // New file successfully written, old one are no longer needed. + mTemporaryBackup.delete(); + + try (FileInputStream mainInStream = mMainInStream; + FileInputStream reserveInStream = mReserveInStream) { + mMainInStream = null; + mReserveInStream = null; + + // Copy main file to reserve. + try (FileOutputStream reserveOutStream = mReserveOutStream) { + mReserveOutStream = null; + FileUtils.copy(mainInStream, reserveOutStream); + finalizeOutStream(reserveOutStream); + } + + // Protect both main and reserve using fs-verity. + try (ParcelFileDescriptor mainPfd = ParcelFileDescriptor.dup(mainInStream.getFD()); + ParcelFileDescriptor copyPfd = ParcelFileDescriptor.dup(reserveInStream.getFD())) { + FileIntegrity.setUpFsVerity(mainPfd); + FileIntegrity.setUpFsVerity(copyPfd); + } catch (IOException e) { + Slog.e(LOG_TAG, "Failed to verity-protect " + mDebugName, e); + } + } catch (IOException e) { + Slog.e(LOG_TAG, "Failed to write reserve copy " + mDebugName + ": " + mReserveCopy, e); + } + } + + public void failWrite(FileOutputStream str) { + if (mMainOutStream != str) { + throw new IllegalStateException("Invalid incoming stream."); + } + + // Close all FDs. + close(); + + // Clean up partially written files + if (mFile.exists()) { + if (!mFile.delete()) { + Slog.i(LOG_TAG, "Failed to clean up mangled file: " + mFile); + } + } + } + + public FileInputStream openRead() throws IOException { + if (mTemporaryBackup.exists()) { + try { + mCurrentFile = mTemporaryBackup; + mCurrentInStream = new FileInputStream(mCurrentFile); + if (mReadEventLogger != null) { + mReadEventLogger.logEvent(Log.INFO, + "Need to read from backup " + mDebugName + " file"); + } + if (mFile.exists()) { + // If both the backup and normal file exist, we + // ignore the normal one since it might have been + // corrupted. + Slog.w(LOG_TAG, "Cleaning up " + mDebugName + " file " + mFile); + mFile.delete(); + } + // Ignore reserve copy as well. + mReserveCopy.delete(); + } catch (java.io.IOException e) { + // We'll try for the normal settings file. + } + } + + if (mCurrentInStream != null) { + return mCurrentInStream; + } + + if (mFile.exists()) { + mCurrentFile = mFile; + mCurrentInStream = new FileInputStream(mCurrentFile); + } else if (mReserveCopy.exists()) { + mCurrentFile = mReserveCopy; + mCurrentInStream = new FileInputStream(mCurrentFile); + if (mReadEventLogger != null) { + mReadEventLogger.logEvent(Log.INFO, + "Need to read from reserve copy " + mDebugName + " file"); + } + } + + if (mCurrentInStream == null) { + if (mReadEventLogger != null) { + mReadEventLogger.logEvent(Log.INFO, "No " + mDebugName + " file"); + } + } + + return mCurrentInStream; + } + + public void failRead(FileInputStream str, Exception e) { + if (mCurrentInStream != str) { + throw new IllegalStateException("Invalid incoming stream."); + } + mCurrentInStream = null; + IoUtils.closeQuietly(str); + + if (mReadEventLogger != null) { + mReadEventLogger.logEvent(Log.ERROR, + "Error reading " + mDebugName + ", removing " + mCurrentFile + '\n' + + Log.getStackTraceString(e)); + } + + mCurrentFile.delete(); + mCurrentFile = null; + } + + public void delete() { + mFile.delete(); + mTemporaryBackup.delete(); + mReserveCopy.delete(); + } + + @Override + public void close() { + IoUtils.closeQuietly(mMainOutStream); + IoUtils.closeQuietly(mMainInStream); + IoUtils.closeQuietly(mReserveOutStream); + IoUtils.closeQuietly(mReserveInStream); + IoUtils.closeQuietly(mCurrentInStream); + mMainOutStream = null; + mMainInStream = null; + mReserveOutStream = null; + mReserveInStream = null; + mCurrentInStream = null; + mCurrentFile = null; + } + + public String toString() { + return mFile.getPath(); + } + + interface ReadEventLogger { + void logEvent(int priority, String msg); + } +} diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java index a13c568f87a6..7ed10a4df1db 100644 --- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java +++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java @@ -18,6 +18,7 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT; import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; import static com.android.server.pm.PackageManagerService.TAG; @@ -55,9 +56,9 @@ import android.util.Slog; import com.android.internal.app.ResolverActivity; import com.android.internal.util.ArrayUtils; -import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; +import com.android.server.am.ActivityManagerUtils; import com.android.server.compat.PlatformCompat; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; @@ -130,18 +131,9 @@ final class ResolveIntentHelper { boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid( ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, filterCallingUid); - String[] categories = intent.getCategories() == null ? new String[0] - : intent.getCategories().toArray(String[]::new); - FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED, - FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, - filterCallingUid, - query.get(i).getComponentInfo().getComponentName().flattenToShortString(), - callerPackage, - intent.getAction(), - categories, - resolvedType, - intent.getScheme(), - hasToBeExportedToMatch); + ActivityManagerUtils.logUnsafeIntentEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, + filterCallingUid, intent, resolvedType, hasToBeExportedToMatch); if (callback != null) { handler.post(() -> { try { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index f1998f764e7c..b6557d000463 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -119,7 +119,6 @@ import com.android.server.pm.resolution.ComponentResolver; import com.android.server.pm.verify.domain.DomainVerificationLegacySettings; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.pm.verify.domain.DomainVerificationPersistence; -import com.android.server.security.FileIntegrity; import com.android.server.utils.Slogf; import com.android.server.utils.Snappable; import com.android.server.utils.SnapshotCache; @@ -172,7 +171,7 @@ import java.util.function.Consumer; /** * Holds information about dynamic settings. */ -public final class Settings implements Watchable, Snappable { +public final class Settings implements Watchable, Snappable, ResilientAtomicFile.ReadEventLogger { private static final String TAG = "PackageSettings"; /** @@ -344,7 +343,7 @@ public final class Settings implements Watchable, Snappable { private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall"; private static final String ATTR_ENABLED = "enabled"; private static final String ATTR_ENABLED_CALLER = "enabledCaller"; - private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus"; + private static final String ATTR_DOMAIN_VERIFICATION_STATE = "domainVerificationStatus"; private static final String ATTR_APP_LINK_GENERATION = "app-link-generation"; private static final String ATTR_INSTALL_REASON = "install-reason"; private static final String ATTR_UNINSTALL_REASON = "uninstall-reason"; @@ -1511,16 +1510,22 @@ public final class Settings implements Watchable, Snappable { return new File(new File(mSystemDir, "users"), Integer.toString(userId)); } - // The method itself does not have to be guarded, but the file does. - @GuardedBy("mPackageRestrictionsLock") - private File getUserPackagesStateFile(int userId) { - return new File(getUserSystemDirectory(userId), "package-restrictions.xml"); + private ResilientAtomicFile getUserPackagesStateFile(int userId) { + File mainFile = new File(getUserSystemDirectory(userId), "package-restrictions.xml"); + File temporaryBackup = new File(getUserSystemDirectory(userId), + "package-restrictions-backup.xml"); + File reserveCopy = new File(getUserSystemDirectory(userId), + "package-restrictions.xml.reservecopy"); + return new ResilientAtomicFile(mainFile, temporaryBackup, reserveCopy, + FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, + "package restrictions", this); } - // The method itself does not have to be guarded, but the file does. - @GuardedBy("mPackageRestrictionsLock") - private File getUserPackagesStateBackupFile(int userId) { - return new File(getUserSystemDirectory(userId), "package-restrictions-backup.xml"); + private ResilientAtomicFile getSettingsFile() { + return new ResilientAtomicFile(mSettingsFilename, mPreviousSettingsFilename, + mSettingsReserveCopyFilename, + FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, + "package manager settings", this); } private File getUserRuntimePermissionsFile(int userId) { @@ -1730,272 +1735,243 @@ public final class Settings implements Watchable, Snappable { } } + @Override + public void logEvent(int priority, String msg) { + mReadMessages.append(msg + "\n"); + PackageManagerService.reportSettingsProblem(priority, msg); + } + + void readPackageRestrictionsLPr(int userId, @NonNull ArrayMap<String, Long> origFirstInstallTimes) { if (DEBUG_MU) { Log.i(TAG, "Reading package restrictions for user=" + userId); } - FileInputStream str = null; - synchronized (mPackageRestrictionsLock) { - File userPackagesStateFile = getUserPackagesStateFile(userId); - File backupFile = getUserPackagesStateBackupFile(userId); - if (backupFile.exists()) { - try { - str = new FileInputStream(backupFile); - mReadMessages.append("Reading from backup stopped packages file\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, - "Need to read from backup stopped packages file"); - if (userPackagesStateFile.exists()) { - // If both the backup and normal file exist, we - // ignore the normal one since it might have been - // corrupted. - Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file " - + userPackagesStateFile); - userPackagesStateFile.delete(); + try (ResilientAtomicFile atomicFile = getUserPackagesStateFile(userId)) { + FileInputStream str = null; + try { + synchronized (mPackageRestrictionsLock) { + str = atomicFile.openRead(); + if (str == null) { + // At first boot, make sure no packages are stopped. + // We usually want to have third party apps initialize + // in the stopped state, but not at first boot. Also + // consider all applications to be installed. + for (PackageSetting pkg : mPackages.values()) { + pkg.setUserState(userId, 0, COMPONENT_ENABLED_STATE_DEFAULT, + true /*installed*/, + false /*stopped*/, + false /*notLaunched*/, + false /*hidden*/, + 0 /*distractionFlags*/, + null /*suspendParams*/, + false /*instantApp*/, + false /*virtualPreload*/, + null /*lastDisableAppCaller*/, + null /*enabledComponents*/, + null /*disabledComponents*/, + PackageManager.INSTALL_REASON_UNKNOWN, + PackageManager.UNINSTALL_REASON_UNKNOWN, + null /*harmfulAppWarning*/, + null /* splashScreenTheme*/, + 0 /*firstInstallTime*/ + ); + } + return; } - } catch (java.io.IOException e) { - // We'll try for the normal settings file. } - } - - if (str == null && userPackagesStateFile.exists()) { - try { - str = new FileInputStream(userPackagesStateFile); - if (DEBUG_MU) Log.i(TAG, "Reading " + userPackagesStateFile); - } catch (java.io.IOException e) { - mReadMessages.append("Error reading: " + e.toString()); - PackageManagerService.reportSettingsProblem(Log.ERROR, - "Error reading settings: " + e); - Slog.wtf(TAG, "Error reading package manager stopped packages", e); - } - } - } - - if (str == null) { - mReadMessages.append("No stopped packages file found\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, - "No stopped packages file; " - + "assuming all started"); - // At first boot, make sure no packages are stopped. - // We usually want to have third party apps initialize - // in the stopped state, but not at first boot. Also - // consider all applications to be installed. - for (PackageSetting pkg : mPackages.values()) { - pkg.setUserState(userId, 0, COMPONENT_ENABLED_STATE_DEFAULT, - true /*installed*/, - false /*stopped*/, - false /*notLaunched*/, - false /*hidden*/, - 0 /*distractionFlags*/, - null /*suspendParams*/, - false /*instantApp*/, - false /*virtualPreload*/, - null /*lastDisableAppCaller*/, - null /*enabledComponents*/, - null /*disabledComponents*/, - PackageManager.INSTALL_REASON_UNKNOWN, - PackageManager.UNINSTALL_REASON_UNKNOWN, - null /*harmfulAppWarning*/, - null /* splashScreenTheme*/, - 0 /*firstInstallTime*/ - ); - } - return; - } - try { - final TypedXmlPullParser parser = Xml.resolvePullParser(str); - - int type; - while ((type=parser.next()) != XmlPullParser.START_TAG - && type != XmlPullParser.END_DOCUMENT) { - ; - } + final TypedXmlPullParser parser = Xml.resolvePullParser(str); - if (type != XmlPullParser.START_TAG) { - mReadMessages.append("No start tag found in package restrictions file\n"); - PackageManagerService.reportSettingsProblem(Log.WARN, - "No start tag found in package manager stopped packages"); - return; - } + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // nothing + } - int outerDepth = parser.getDepth(); - PackageSetting ps = null; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; + if (type != XmlPullParser.START_TAG) { + mReadMessages.append("No start tag found in package restrictions file\n"); + PackageManagerService.reportSettingsProblem(Log.WARN, + "No start tag found in package manager package restrictions file"); + return; } - String tagName = parser.getName(); - if (tagName.equals(TAG_PACKAGE)) { - String name = parser.getAttributeValue(null, ATTR_NAME); - ps = mPackages.get(name); - if (ps == null) { - Slog.w(PackageManagerService.TAG, "No package known for stopped package " - + name); - XmlUtils.skipCurrentTag(parser); + int outerDepth = parser.getDepth(); + PackageSetting ps = null; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { continue; } - final long ceDataInode = - parser.getAttributeLong(null, ATTR_CE_DATA_INODE, 0); - final boolean installed = - parser.getAttributeBoolean(null, ATTR_INSTALLED, true); - final boolean stopped = - parser.getAttributeBoolean(null, ATTR_STOPPED, false); - final boolean notLaunched = - parser.getAttributeBoolean(null, ATTR_NOT_LAUNCHED, false); - - // For backwards compatibility with the previous name of "blocked", which - // now means hidden, read the old attribute as well. - boolean hidden = parser.getAttributeBoolean(null, ATTR_HIDDEN, false); - if (!hidden) { - hidden = parser.getAttributeBoolean(null, ATTR_BLOCKED, false); - } + String tagName = parser.getName(); + if (tagName.equals(TAG_PACKAGE)) { + String name = parser.getAttributeValue(null, ATTR_NAME); + ps = mPackages.get(name); + if (ps == null) { + Slog.w(PackageManagerService.TAG, + "No package known for package restrictions " + name); + XmlUtils.skipCurrentTag(parser); + continue; + } - final int distractionFlags = parser.getAttributeInt(null, ATTR_DISTRACTION_FLAGS, 0); - final boolean suspended = parser.getAttributeBoolean(null, ATTR_SUSPENDED, false); - String oldSuspendingPackage = parser.getAttributeValue(null, - ATTR_SUSPENDING_PACKAGE); - final String dialogMessage = parser.getAttributeValue(null, - ATTR_SUSPEND_DIALOG_MESSAGE); - if (suspended && oldSuspendingPackage == null) { - oldSuspendingPackage = PLATFORM_PACKAGE_NAME; - } + final long ceDataInode = + parser.getAttributeLong(null, ATTR_CE_DATA_INODE, 0); + final boolean installed = + parser.getAttributeBoolean(null, ATTR_INSTALLED, true); + final boolean stopped = + parser.getAttributeBoolean(null, ATTR_STOPPED, false); + final boolean notLaunched = + parser.getAttributeBoolean(null, ATTR_NOT_LAUNCHED, false); + + // For backwards compatibility with the previous name of "blocked", which + // now means hidden, read the old attribute as well. + boolean hidden = parser.getAttributeBoolean(null, ATTR_HIDDEN, false); + if (!hidden) { + hidden = parser.getAttributeBoolean(null, ATTR_BLOCKED, false); + } - final boolean blockUninstall = - parser.getAttributeBoolean(null, ATTR_BLOCK_UNINSTALL, false); - final boolean instantApp = - parser.getAttributeBoolean(null, ATTR_INSTANT_APP, false); - final boolean virtualPreload = - parser.getAttributeBoolean(null, ATTR_VIRTUAL_PRELOAD, false); - final int enabled = parser.getAttributeInt(null, ATTR_ENABLED, - COMPONENT_ENABLED_STATE_DEFAULT); - final String enabledCaller = parser.getAttributeValue(null, - ATTR_ENABLED_CALLER); - final String harmfulAppWarning = - parser.getAttributeValue(null, ATTR_HARMFUL_APP_WARNING); - final int verifState = parser.getAttributeInt(null, - ATTR_DOMAIN_VERIFICATON_STATE, - PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); - final int installReason = parser.getAttributeInt(null, ATTR_INSTALL_REASON, - PackageManager.INSTALL_REASON_UNKNOWN); - final int uninstallReason = parser.getAttributeInt(null, ATTR_UNINSTALL_REASON, - PackageManager.UNINSTALL_REASON_UNKNOWN); - final String splashScreenTheme = parser.getAttributeValue(null, - ATTR_SPLASH_SCREEN_THEME); - final long firstInstallTime = parser.getAttributeLongHex(null, - ATTR_FIRST_INSTALL_TIME, 0); - - ArraySet<String> enabledComponents = null; - ArraySet<String> disabledComponents = null; - PersistableBundle suspendedAppExtras = null; - PersistableBundle suspendedLauncherExtras = null; - SuspendDialogInfo oldSuspendDialogInfo = null; - - int packageDepth = parser.getDepth(); - ArrayMap<String, SuspendParams> suspendParamsMap = null; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > packageDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; + final int distractionFlags = parser.getAttributeInt(null, + ATTR_DISTRACTION_FLAGS, 0); + final boolean suspended = parser.getAttributeBoolean(null, ATTR_SUSPENDED, + false); + String oldSuspendingPackage = parser.getAttributeValue(null, + ATTR_SUSPENDING_PACKAGE); + final String dialogMessage = parser.getAttributeValue(null, + ATTR_SUSPEND_DIALOG_MESSAGE); + if (suspended && oldSuspendingPackage == null) { + oldSuspendingPackage = PLATFORM_PACKAGE_NAME; } - switch (parser.getName()) { - case TAG_ENABLED_COMPONENTS: - enabledComponents = readComponentsLPr(parser); - break; - case TAG_DISABLED_COMPONENTS: - disabledComponents = readComponentsLPr(parser); - break; - case TAG_SUSPENDED_APP_EXTRAS: - suspendedAppExtras = PersistableBundle.restoreFromXml(parser); - break; - case TAG_SUSPENDED_LAUNCHER_EXTRAS: - suspendedLauncherExtras = PersistableBundle.restoreFromXml(parser); - break; - case TAG_SUSPENDED_DIALOG_INFO: - oldSuspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser); - break; - case TAG_SUSPEND_PARAMS: - final String suspendingPackage = parser.getAttributeValue(null, - ATTR_SUSPENDING_PACKAGE); - if (suspendingPackage == null) { - Slog.wtf(TAG, "No suspendingPackage found inside tag " - + TAG_SUSPEND_PARAMS); - continue; - } - if (suspendParamsMap == null) { - suspendParamsMap = new ArrayMap<>(); - } - suspendParamsMap.put(suspendingPackage, - SuspendParams.restoreFromXml(parser)); - break; - default: - Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag " - + TAG_PACKAGE); + + final boolean blockUninstall = + parser.getAttributeBoolean(null, ATTR_BLOCK_UNINSTALL, false); + final boolean instantApp = + parser.getAttributeBoolean(null, ATTR_INSTANT_APP, false); + final boolean virtualPreload = + parser.getAttributeBoolean(null, ATTR_VIRTUAL_PRELOAD, false); + final int enabled = parser.getAttributeInt(null, ATTR_ENABLED, + COMPONENT_ENABLED_STATE_DEFAULT); + final String enabledCaller = parser.getAttributeValue(null, + ATTR_ENABLED_CALLER); + final String harmfulAppWarning = + parser.getAttributeValue(null, ATTR_HARMFUL_APP_WARNING); + final int verifState = parser.getAttributeInt(null, + ATTR_DOMAIN_VERIFICATION_STATE, + PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); + final int installReason = parser.getAttributeInt(null, ATTR_INSTALL_REASON, + PackageManager.INSTALL_REASON_UNKNOWN); + final int uninstallReason = parser.getAttributeInt(null, + ATTR_UNINSTALL_REASON, + PackageManager.UNINSTALL_REASON_UNKNOWN); + final String splashScreenTheme = parser.getAttributeValue(null, + ATTR_SPLASH_SCREEN_THEME); + final long firstInstallTime = parser.getAttributeLongHex(null, + ATTR_FIRST_INSTALL_TIME, 0); + + ArraySet<String> enabledComponents = null; + ArraySet<String> disabledComponents = null; + PersistableBundle suspendedAppExtras = null; + PersistableBundle suspendedLauncherExtras = null; + SuspendDialogInfo oldSuspendDialogInfo = null; + + int packageDepth = parser.getDepth(); + ArrayMap<String, SuspendParams> suspendParamsMap = null; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > packageDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + switch (parser.getName()) { + case TAG_ENABLED_COMPONENTS: + enabledComponents = readComponentsLPr(parser); + break; + case TAG_DISABLED_COMPONENTS: + disabledComponents = readComponentsLPr(parser); + break; + case TAG_SUSPENDED_APP_EXTRAS: + suspendedAppExtras = PersistableBundle.restoreFromXml(parser); + break; + case TAG_SUSPENDED_LAUNCHER_EXTRAS: + suspendedLauncherExtras = PersistableBundle.restoreFromXml( + parser); + break; + case TAG_SUSPENDED_DIALOG_INFO: + oldSuspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser); + break; + case TAG_SUSPEND_PARAMS: + final String suspendingPackage = parser.getAttributeValue(null, + ATTR_SUSPENDING_PACKAGE); + if (suspendingPackage == null) { + Slog.wtf(TAG, "No suspendingPackage found inside tag " + + TAG_SUSPEND_PARAMS); + continue; + } + if (suspendParamsMap == null) { + suspendParamsMap = new ArrayMap<>(); + } + suspendParamsMap.put(suspendingPackage, + SuspendParams.restoreFromXml(parser)); + break; + default: + Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag " + + TAG_PACKAGE); + } + } + if (oldSuspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) { + oldSuspendDialogInfo = new SuspendDialogInfo.Builder() + .setMessage(dialogMessage) + .build(); + } + if (suspended && suspendParamsMap == null) { + final SuspendParams suspendParams = new SuspendParams( + oldSuspendDialogInfo, + suspendedAppExtras, + suspendedLauncherExtras); + suspendParamsMap = new ArrayMap<>(); + suspendParamsMap.put(oldSuspendingPackage, suspendParams); } - } - if (oldSuspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) { - oldSuspendDialogInfo = new SuspendDialogInfo.Builder() - .setMessage(dialogMessage) - .build(); - } - if (suspended && suspendParamsMap == null) { - final SuspendParams suspendParams = new SuspendParams( - oldSuspendDialogInfo, - suspendedAppExtras, - suspendedLauncherExtras); - suspendParamsMap = new ArrayMap<>(); - suspendParamsMap.put(oldSuspendingPackage, suspendParams); - } - if (blockUninstall) { - setBlockUninstallLPw(userId, name, true); + if (blockUninstall) { + setBlockUninstallLPw(userId, name, true); + } + ps.setUserState(userId, ceDataInode, enabled, installed, stopped, + notLaunched, + hidden, distractionFlags, suspendParamsMap, instantApp, + virtualPreload, + enabledCaller, enabledComponents, disabledComponents, installReason, + uninstallReason, harmfulAppWarning, splashScreenTheme, + firstInstallTime != 0 ? firstInstallTime : + origFirstInstallTimes.getOrDefault(name, 0L)); + + mDomainVerificationManager.setLegacyUserState(name, userId, verifState); + } else if (tagName.equals("preferred-activities")) { + readPreferredActivitiesLPw(parser, userId); + } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { + readPersistentPreferredActivitiesLPw(parser, userId); + } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) { + readCrossProfileIntentFiltersLPw(parser, userId); + } else if (tagName.equals(TAG_DEFAULT_APPS)) { + readDefaultAppsLPw(parser, userId); + } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) { + readBlockUninstallPackagesLPw(parser, userId); + } else { + Slog.w(PackageManagerService.TAG, + "Unknown element under <stopped-packages>: " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); } - ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched, - hidden, distractionFlags, suspendParamsMap, instantApp, virtualPreload, - enabledCaller, enabledComponents, disabledComponents, installReason, - uninstallReason, harmfulAppWarning, splashScreenTheme, - firstInstallTime != 0 ? firstInstallTime : - origFirstInstallTimes.getOrDefault(name, 0L)); - - mDomainVerificationManager.setLegacyUserState(name, userId, verifState); - } else if (tagName.equals("preferred-activities")) { - readPreferredActivitiesLPw(parser, userId); - } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { - readPersistentPreferredActivitiesLPw(parser, userId); - } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) { - readCrossProfileIntentFiltersLPw(parser, userId); - } else if (tagName.equals(TAG_DEFAULT_APPS)) { - readDefaultAppsLPw(parser, userId); - } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) { - readBlockUninstallPackagesLPw(parser, userId); - } else { - Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); } - } - - str.close(); - } catch (XmlPullParserException e) { - mReadMessages.append("Error reading: " + e.toString()); - PackageManagerService.reportSettingsProblem(Log.ERROR, - "Error reading stopped packages: " + e); - Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", - e); + } catch (IOException | XmlPullParserException e) { + // Remove corrupted file and retry. + atomicFile.failRead(str, e); - } catch (java.io.IOException e) { - mReadMessages.append("Error reading: " + e.toString()); - PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", - e); + readPackageRestrictionsLPr(userId, origFirstInstallTimes); + } } } @@ -2165,219 +2141,176 @@ public final class Settings implements Watchable, Snappable { Log.i(TAG, "Writing package restrictions for user=" + userId); } - final File userPackagesStateFile; - final File backupFile; - final FileOutputStream fstr; - - synchronized (mPackageRestrictionsLock) { - if (!sync) { - int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) - 1; - if (pending < 0) { - Log.i(TAG, "Cancel writing package restrictions for user=" + userId); - return; - } - mPendingAsyncPackageRestrictionsWrites.put(userId, pending); - } + FileOutputStream str = null; + try (ResilientAtomicFile atomicFile = getUserPackagesStateFile(userId)) { + try { + synchronized (mPackageRestrictionsLock) { + if (!sync) { + int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) - 1; + if (pending < 0) { + Log.i(TAG, "Cancel writing package restrictions for user=" + userId); + return; + } + mPendingAsyncPackageRestrictionsWrites.put(userId, pending); + } - // Keep the old stopped packages around until we know the new ones have - // been successfully written. - userPackagesStateFile = getUserPackagesStateFile(userId); - backupFile = getUserPackagesStateBackupFile(userId); - new File(userPackagesStateFile.getParent()).mkdirs(); - if (userPackagesStateFile.exists()) { - // Presence of backup settings file indicates that we failed - // to persist packages earlier. So preserve the older - // backup for future reference since the current packages - // might have been corrupted. - if (!backupFile.exists()) { - if (!userPackagesStateFile.renameTo(backupFile)) { + try { + str = atomicFile.startWrite(); + } catch (java.io.IOException e) { Slog.wtf(PackageManagerService.TAG, - "Unable to backup user packages state file, " - + "current changes will be lost at reboot"); + "Unable to write package manager package restrictions, " + + " current changes will be lost at reboot", e); return; } - } else { - userPackagesStateFile.delete(); - Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup"); } - } - - try { - fstr = new FileOutputStream(userPackagesStateFile); - // File is created, set permissions. - FileUtils.setPermissions(userPackagesStateFile.toString(), - FileUtils.S_IRUSR | FileUtils.S_IWUSR - | FileUtils.S_IRGRP | FileUtils.S_IWGRP, - -1, -1); - } catch (java.io.IOException e) { - Slog.wtf(PackageManagerService.TAG, - "Unable to write package manager user packages state, " - + " current changes will be lost at reboot", e); - return; - } - } - try { - synchronized (mLock) { - final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr); - serializer.startDocument(null, true); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", - true); + synchronized (mLock) { + final TypedXmlSerializer serializer = Xml.resolveSerializer(str); + serializer.startDocument(null, true); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", + true); - serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS); + serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS); - if (DEBUG_MU) { - Slogf.i(TAG, "Writing %s (%d packages)", userPackagesStateFile, - mPackages.values().size()); - } - for (final PackageSetting pkg : mPackages.values()) { - final PackageUserStateInternal ustate = pkg.readUserState(userId); if (DEBUG_MU) { - Log.v(TAG, " pkg=" + pkg.getPackageName() - + ", installed=" + ustate.isInstalled() - + ", state=" + ustate.getEnabledState()); + Slogf.i(TAG, "Writing %s (%d packages)", atomicFile, + mPackages.values().size()); } + for (final PackageSetting pkg : mPackages.values()) { + final PackageUserStateInternal ustate = pkg.readUserState(userId); + if (DEBUG_MU) { + Log.v(TAG, " pkg=" + pkg.getPackageName() + + ", installed=" + ustate.isInstalled() + + ", state=" + ustate.getEnabledState()); + } - serializer.startTag(null, TAG_PACKAGE); - serializer.attribute(null, ATTR_NAME, pkg.getPackageName()); - if (ustate.getCeDataInode() != 0) { - serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.getCeDataInode()); - } - if (!ustate.isInstalled()) { - serializer.attributeBoolean(null, ATTR_INSTALLED, false); - } - if (ustate.isStopped()) { - serializer.attributeBoolean(null, ATTR_STOPPED, true); - } - if (ustate.isNotLaunched()) { - serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true); - } - if (ustate.isHidden()) { - serializer.attributeBoolean(null, ATTR_HIDDEN, true); - } - if (ustate.getDistractionFlags() != 0) { - serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS, - ustate.getDistractionFlags()); - } - if (ustate.isSuspended()) { - serializer.attributeBoolean(null, ATTR_SUSPENDED, true); - } - if (ustate.isInstantApp()) { - serializer.attributeBoolean(null, ATTR_INSTANT_APP, true); - } - if (ustate.isVirtualPreload()) { - serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true); - } - if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState()); - if (ustate.getLastDisableAppCaller() != null) { - serializer.attribute(null, ATTR_ENABLED_CALLER, - ustate.getLastDisableAppCaller()); + serializer.startTag(null, TAG_PACKAGE); + serializer.attribute(null, ATTR_NAME, pkg.getPackageName()); + if (ustate.getCeDataInode() != 0) { + serializer.attributeLong(null, ATTR_CE_DATA_INODE, + ustate.getCeDataInode()); } - } - if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) { - serializer.attributeInt(null, ATTR_INSTALL_REASON, - ustate.getInstallReason()); - } - serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME, - ustate.getFirstInstallTimeMillis()); - if (ustate.getUninstallReason() != PackageManager.UNINSTALL_REASON_UNKNOWN) { - serializer.attributeInt(null, ATTR_UNINSTALL_REASON, - ustate.getUninstallReason()); - } - if (ustate.getHarmfulAppWarning() != null) { - serializer.attribute(null, ATTR_HARMFUL_APP_WARNING, - ustate.getHarmfulAppWarning()); - } - if (ustate.getSplashScreenTheme() != null) { - serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME, - ustate.getSplashScreenTheme()); - } - if (ustate.isSuspended()) { - for (int i = 0; i < ustate.getSuspendParams().size(); i++) { - final String suspendingPackage = ustate.getSuspendParams().keyAt(i); - serializer.startTag(null, TAG_SUSPEND_PARAMS); - serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, suspendingPackage); - final SuspendParams params = - ustate.getSuspendParams().valueAt(i); - if (params != null) { - params.saveToXml(serializer); + if (!ustate.isInstalled()) { + serializer.attributeBoolean(null, ATTR_INSTALLED, false); + } + if (ustate.isStopped()) { + serializer.attributeBoolean(null, ATTR_STOPPED, true); + } + if (ustate.isNotLaunched()) { + serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true); + } + if (ustate.isHidden()) { + serializer.attributeBoolean(null, ATTR_HIDDEN, true); + } + if (ustate.getDistractionFlags() != 0) { + serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS, + ustate.getDistractionFlags()); + } + if (ustate.isSuspended()) { + serializer.attributeBoolean(null, ATTR_SUSPENDED, true); + } + if (ustate.isInstantApp()) { + serializer.attributeBoolean(null, ATTR_INSTANT_APP, true); + } + if (ustate.isVirtualPreload()) { + serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true); + } + if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) { + serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState()); + if (ustate.getLastDisableAppCaller() != null) { + serializer.attribute(null, ATTR_ENABLED_CALLER, + ustate.getLastDisableAppCaller()); } - serializer.endTag(null, TAG_SUSPEND_PARAMS); } - } - final ArraySet<String> enabledComponents = ustate.getEnabledComponents(); - if (enabledComponents != null && enabledComponents.size() > 0) { - serializer.startTag(null, TAG_ENABLED_COMPONENTS); - for (int i = 0; i < enabledComponents.size(); i++) { - serializer.startTag(null, TAG_ITEM); - serializer.attribute(null, ATTR_NAME, - enabledComponents.valueAt(i)); - serializer.endTag(null, TAG_ITEM); + if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) { + serializer.attributeInt(null, ATTR_INSTALL_REASON, + ustate.getInstallReason()); } - serializer.endTag(null, TAG_ENABLED_COMPONENTS); - } - final ArraySet<String> disabledComponents = ustate.getDisabledComponents(); - if (disabledComponents != null && disabledComponents.size() > 0) { - serializer.startTag(null, TAG_DISABLED_COMPONENTS); - for (int i = 0; i < disabledComponents.size(); i++) { - serializer.startTag(null, TAG_ITEM); - serializer.attribute(null, ATTR_NAME, - disabledComponents.valueAt(i)); - serializer.endTag(null, TAG_ITEM); + serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME, + ustate.getFirstInstallTimeMillis()); + if (ustate.getUninstallReason() + != PackageManager.UNINSTALL_REASON_UNKNOWN) { + serializer.attributeInt(null, ATTR_UNINSTALL_REASON, + ustate.getUninstallReason()); + } + if (ustate.getHarmfulAppWarning() != null) { + serializer.attribute(null, ATTR_HARMFUL_APP_WARNING, + ustate.getHarmfulAppWarning()); + } + if (ustate.getSplashScreenTheme() != null) { + serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME, + ustate.getSplashScreenTheme()); + } + if (ustate.isSuspended()) { + for (int i = 0; i < ustate.getSuspendParams().size(); i++) { + final String suspendingPackage = ustate.getSuspendParams().keyAt(i); + serializer.startTag(null, TAG_SUSPEND_PARAMS); + serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, + suspendingPackage); + final SuspendParams params = + ustate.getSuspendParams().valueAt(i); + if (params != null) { + params.saveToXml(serializer); + } + serializer.endTag(null, TAG_SUSPEND_PARAMS); + } + } + final ArraySet<String> enabledComponents = ustate.getEnabledComponents(); + if (enabledComponents != null && enabledComponents.size() > 0) { + serializer.startTag(null, TAG_ENABLED_COMPONENTS); + for (int i = 0; i < enabledComponents.size(); i++) { + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, + enabledComponents.valueAt(i)); + serializer.endTag(null, TAG_ITEM); + } + serializer.endTag(null, TAG_ENABLED_COMPONENTS); + } + final ArraySet<String> disabledComponents = ustate.getDisabledComponents(); + if (disabledComponents != null && disabledComponents.size() > 0) { + serializer.startTag(null, TAG_DISABLED_COMPONENTS); + for (int i = 0; i < disabledComponents.size(); i++) { + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, + disabledComponents.valueAt(i)); + serializer.endTag(null, TAG_ITEM); + } + serializer.endTag(null, TAG_DISABLED_COMPONENTS); } - serializer.endTag(null, TAG_DISABLED_COMPONENTS); - } - - serializer.endTag(null, TAG_PACKAGE); - } - writePreferredActivitiesLPr(serializer, userId, true); - writePersistentPreferredActivitiesLPr(serializer, userId); - writeCrossProfileIntentFiltersLPr(serializer, userId); - writeDefaultAppsLPr(serializer, userId); - writeBlockUninstallPackagesLPr(serializer, userId); + serializer.endTag(null, TAG_PACKAGE); + } - serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS); + writePreferredActivitiesLPr(serializer, userId, true); + writePersistentPreferredActivitiesLPr(serializer, userId); + writeCrossProfileIntentFiltersLPr(serializer, userId); + writeDefaultAppsLPr(serializer, userId); + writeBlockUninstallPackagesLPr(serializer, userId); - serializer.endDocument(); - } + serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS); - fstr.flush(); - FileUtils.sync(fstr); - IoUtils.closeQuietly(fstr); + serializer.endDocument(); + } - synchronized (mPackageRestrictionsLock) { - // File is created, set permissions. - FileUtils.setPermissions(userPackagesStateFile.toString(), - FileUtils.S_IRUSR | FileUtils.S_IWUSR - | FileUtils.S_IRGRP | FileUtils.S_IWGRP, - -1, -1); - // New settings successfully written, old ones are no longer needed. - backupFile.delete(); - } + atomicFile.finishWrite(str); - if (DEBUG_MU) { - Log.i(TAG, "New settings successfully written for user=" + userId + ": " - + userPackagesStateFile); - } + if (DEBUG_MU) { + Log.i(TAG, "New package restrictions successfully written for user=" + userId + + ": " + atomicFile); + } - com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( - "package-user-" + userId, SystemClock.uptimeMillis() - startTime); + com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( + "package-user-" + userId, SystemClock.uptimeMillis() - startTime); - // Done, all is good! - return; - } catch (java.io.IOException e) { - Slog.wtf(PackageManagerService.TAG, - "Unable to write package manager user packages state, " - + " current changes will be lost at reboot", e); - } - - // Clean up partially written files - if (userPackagesStateFile.exists()) { - if (!userPackagesStateFile.delete()) { - Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " - + mStoppedPackagesFilename); + // Done, all is good! + return; + } catch (java.io.IOException e) { + Slog.wtf(PackageManagerService.TAG, + "Unable to write package manager package restrictions, " + + " current changes will be lost at reboot", e); + if (str != null) { + atomicFile.failWrite(str); + } } } } @@ -2589,153 +2522,108 @@ public final class Settings implements Watchable, Snappable { // right time. invalidatePackageCache(); - // Keep the old settings around until we know the new ones have - // been successfully written. - if (mSettingsFilename.exists()) { - // Presence of backup settings file indicates that we failed - // to persist settings earlier. So preserve the older - // backup for future reference since the current settings - // might have been corrupted. - if (!mPreviousSettingsFilename.exists()) { - if (!mSettingsFilename.renameTo(mPreviousSettingsFilename)) { - Slog.wtf(PackageManagerService.TAG, - "Unable to store older package manager settings, " - + " current changes will be lost at reboot"); - return; - } - } else { - mSettingsFilename.delete(); - Slog.w(PackageManagerService.TAG, "Preserving older settings backup"); - } - } - mPastSignatures.clear(); - try { - final FileOutputStream fstr = new FileOutputStream(mSettingsFilename); - final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr); - serializer.startDocument(null, true); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - - serializer.startTag(null, "packages"); - - for (int i = 0; i < mVersion.size(); i++) { - final String volumeUuid = mVersion.keyAt(i); - final VersionInfo ver = mVersion.valueAt(i); - - serializer.startTag(null, TAG_VERSION); - XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid); - serializer.attributeInt(null, ATTR_SDK_VERSION, ver.sdkVersion); - serializer.attributeInt(null, ATTR_DATABASE_VERSION, ver.databaseVersion); - XmlUtils.writeStringAttribute(serializer, ATTR_BUILD_FINGERPRINT, - ver.buildFingerprint); - XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint); - serializer.endTag(null, TAG_VERSION); - } + try (ResilientAtomicFile atomicFile = getSettingsFile()) { + FileOutputStream str = null; + try { + str = atomicFile.startWrite(); - if (mVerifierDeviceIdentity != null) { - serializer.startTag(null, "verifier"); - serializer.attribute(null, "device", mVerifierDeviceIdentity.toString()); - serializer.endTag(null, "verifier"); - } + final TypedXmlSerializer serializer = Xml.resolveSerializer(str); + serializer.startDocument(null, true); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", + true); - serializer.startTag(null, "permission-trees"); - mPermissions.writePermissionTrees(serializer); - serializer.endTag(null, "permission-trees"); + serializer.startTag(null, "packages"); - serializer.startTag(null, "permissions"); - mPermissions.writePermissions(serializer); - serializer.endTag(null, "permissions"); + for (int i = 0; i < mVersion.size(); i++) { + final String volumeUuid = mVersion.keyAt(i); + final VersionInfo ver = mVersion.valueAt(i); - for (final PackageSetting pkg : mPackages.values()) { - if (pkg.getPkg() != null && pkg.getPkg().isApex()) { - // Don't persist APEX which doesn't have a valid app id and will fail to load - continue; + serializer.startTag(null, TAG_VERSION); + XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid); + serializer.attributeInt(null, ATTR_SDK_VERSION, ver.sdkVersion); + serializer.attributeInt(null, ATTR_DATABASE_VERSION, ver.databaseVersion); + XmlUtils.writeStringAttribute(serializer, ATTR_BUILD_FINGERPRINT, + ver.buildFingerprint); + XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint); + serializer.endTag(null, TAG_VERSION); } - writePackageLPr(serializer, pkg); - } - for (final PackageSetting pkg : mDisabledSysPackages.values()) { - if (pkg.getPkg() != null && pkg.getPkg().isApex()) { - // Don't persist APEX which doesn't have a valid app id and will fail to load - continue; + if (mVerifierDeviceIdentity != null) { + serializer.startTag(null, "verifier"); + serializer.attribute(null, "device", mVerifierDeviceIdentity.toString()); + serializer.endTag(null, "verifier"); } - writeDisabledSysPackageLPr(serializer, pkg); - } - for (final SharedUserSetting usr : mSharedUsers.values()) { - serializer.startTag(null, "shared-user"); - serializer.attribute(null, ATTR_NAME, usr.name); - serializer.attributeInt(null, "userId", usr.mAppId); - usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage()); - serializer.endTag(null, "shared-user"); - } + serializer.startTag(null, "permission-trees"); + mPermissions.writePermissionTrees(serializer); + serializer.endTag(null, "permission-trees"); - if (mRenamedPackages.size() > 0) { - for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) { - serializer.startTag(null, "renamed-package"); - serializer.attribute(null, "new", e.getKey()); - serializer.attribute(null, "old", e.getValue()); - serializer.endTag(null, "renamed-package"); + serializer.startTag(null, "permissions"); + mPermissions.writePermissions(serializer); + serializer.endTag(null, "permissions"); + + for (final PackageSetting pkg : mPackages.values()) { + if (pkg.getPkg() != null && pkg.getPkg().isApex()) { + // Don't persist APEX which doesn't have a valid app id and will fail to + // load + continue; + } + writePackageLPr(serializer, pkg); } - } - mDomainVerificationManager.writeSettings(computer, serializer, - false /* includeSignatures */, UserHandle.USER_ALL); + for (final PackageSetting pkg : mDisabledSysPackages.values()) { + if (pkg.getPkg() != null && pkg.getPkg().isApex()) { + // Don't persist APEX which doesn't have a valid app id and will fail to + // load + continue; + } + writeDisabledSysPackageLPr(serializer, pkg); + } - mKeySetManagerService.writeKeySetManagerServiceLPr(serializer); + for (final SharedUserSetting usr : mSharedUsers.values()) { + serializer.startTag(null, "shared-user"); + serializer.attribute(null, ATTR_NAME, usr.name); + serializer.attributeInt(null, "userId", usr.mAppId); + usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage()); + serializer.endTag(null, "shared-user"); + } - serializer.endTag(null, "packages"); + if (mRenamedPackages.size() > 0) { + for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) { + serializer.startTag(null, "renamed-package"); + serializer.attribute(null, "new", e.getKey()); + serializer.attribute(null, "old", e.getValue()); + serializer.endTag(null, "renamed-package"); + } + } - serializer.endDocument(); + mDomainVerificationManager.writeSettings(computer, serializer, + false /* includeSignatures */, UserHandle.USER_ALL); - fstr.flush(); - FileUtils.sync(fstr); - fstr.close(); + mKeySetManagerService.writeKeySetManagerServiceLPr(serializer); - // New settings successfully written, old ones are no longer needed. - mPreviousSettingsFilename.delete(); - mSettingsReserveCopyFilename.delete(); + serializer.endTag(null, "packages"); - FileUtils.setPermissions(mSettingsFilename.toString(), - FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, - -1, -1); + serializer.endDocument(); - try (FileInputStream in = new FileInputStream(mSettingsFilename); - FileOutputStream out = new FileOutputStream(mSettingsReserveCopyFilename)) { - FileUtils.copy(in, out); - out.flush(); - FileUtils.sync(out); - } catch (IOException e) { - Slog.e(TAG, - "Failed to write reserve copy of settings: " + mSettingsReserveCopyFilename, - e); - } + atomicFile.finishWrite(str); - try { - FileIntegrity.setUpFsVerity(mSettingsFilename); - FileIntegrity.setUpFsVerity(mSettingsReserveCopyFilename); - } catch (IOException e) { - Slog.e(TAG, "Failed to verity-protect settings", e); - } - - writeKernelMappingLPr(); - writePackageListLPr(); - writeAllUsersPackageRestrictionsLPr(sync); - writeAllRuntimePermissionsLPr(); - com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( - "package", SystemClock.uptimeMillis() - startTime); - return; + writeKernelMappingLPr(); + writePackageListLPr(); + writeAllUsersPackageRestrictionsLPr(sync); + writeAllRuntimePermissionsLPr(); + com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( + "package", SystemClock.uptimeMillis() - startTime); + return; - } catch(java.io.IOException e) { - Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, " - + "current changes will be lost at reboot", e); - } - // Clean up partially written files - if (mSettingsFilename.exists()) { - if (!mSettingsFilename.delete()) { - Slog.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " - + mSettingsFilename); + } catch (java.io.IOException e) { + Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, " + + "current changes will be lost at reboot", e); + if (str != null) { + atomicFile.failWrite(str); + } } } //Debug.stopMethodTracing(); @@ -3160,183 +3048,140 @@ public final class Settings implements Watchable, Snappable { mInstallerPackages.clear(); originalFirstInstallTimes.clear(); - File file = null; - FileInputStream str = null; - - try { - // Check if the previous write was incomplete. - if (mPreviousSettingsFilename.exists()) { - try { - file = mPreviousSettingsFilename; - str = new FileInputStream(file); - mReadMessages.append("Reading from backup settings file\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, - "Need to read from backup settings file"); - if (mSettingsFilename.exists()) { - // If both the previous and current settings files exist, - // we ignore the current since it might have been corrupted. - Slog.w(PackageManagerService.TAG, "Cleaning up settings file " - + mSettingsFilename); - mSettingsFilename.delete(); - } - // Ignore reserve copy as well. - mSettingsReserveCopyFilename.delete(); - } catch (java.io.IOException e) { - // We'll try for the normal settings file. - } - } - if (str == null) { - if (mSettingsFilename.exists()) { - // Using packages.xml. - file = mSettingsFilename; - str = new FileInputStream(file); - } else if (mSettingsReserveCopyFilename.exists()) { - // Using reserve copy. - file = mSettingsReserveCopyFilename; - str = new FileInputStream(file); - mReadMessages.append("Reading from reserve copy settings file\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, - "Need to read from reserve copy settings file"); + try (ResilientAtomicFile atomicFile = getSettingsFile()) { + FileInputStream str = null; + try { + str = atomicFile.openRead(); + if (str == null) { + // Not necessary, but will avoid wtf-s in the "finally" section. + findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); + findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); + return false; } - } - if (str == null) { - // No available data sources. - mReadMessages.append("No settings file found\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, - "No settings file; creating initial state"); - // Not necessary, but will avoid wtf-s in the "finally" section. - findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); - findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); - return false; - } - final TypedXmlPullParser parser = Xml.resolvePullParser(str); + final TypedXmlPullParser parser = Xml.resolvePullParser(str); - int type; - while ((type = parser.next()) != XmlPullParser.START_TAG - && type != XmlPullParser.END_DOCUMENT) { - ; - } - - if (type != XmlPullParser.START_TAG) { - mReadMessages.append("No start tag found in settings file\n"); - PackageManagerService.reportSettingsProblem(Log.WARN, - "No start tag found in package manager settings"); - Slog.wtf(PackageManagerService.TAG, - "No start tag found in package manager settings"); - return false; - } + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // nothing + } - int outerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; + if (type != XmlPullParser.START_TAG) { + mReadMessages.append("No start tag found in settings file\n"); + PackageManagerService.reportSettingsProblem(Log.WARN, + "No start tag found in package manager settings"); + Slog.wtf(PackageManagerService.TAG, + "No start tag found in package manager settings"); + return false; } - String tagName = parser.getName(); - if (tagName.equals("package")) { - readPackageLPw(parser, users, originalFirstInstallTimes); - } else if (tagName.equals("permissions")) { - mPermissions.readPermissions(parser); - } else if (tagName.equals("permission-trees")) { - mPermissions.readPermissionTrees(parser); - } else if (tagName.equals("shared-user")) { - readSharedUserLPw(parser, users); - } else if (tagName.equals("preferred-packages")) { - // no longer used. - } else if (tagName.equals("preferred-activities")) { - // Upgrading from old single-user implementation; - // these are the preferred activities for user 0. - readPreferredActivitiesLPw(parser, 0); - } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { - // TODO: check whether this is okay! as it is very - // similar to how preferred-activities are treated - readPersistentPreferredActivitiesLPw(parser, 0); - } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) { - // TODO: check whether this is okay! as it is very - // similar to how preferred-activities are treated - readCrossProfileIntentFiltersLPw(parser, 0); - } else if (tagName.equals(TAG_DEFAULT_BROWSER)) { - readDefaultAppsLPw(parser, 0); - } else if (tagName.equals("updated-package")) { - readDisabledSysPackageLPw(parser, users); - } else if (tagName.equals("renamed-package")) { - String nname = parser.getAttributeValue(null, "new"); - String oname = parser.getAttributeValue(null, "old"); - if (nname != null && oname != null) { - mRenamedPackages.put(nname, oname); + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; } - } else if (tagName.equals("last-platform-version")) { - // Upgrade from older XML schema - final VersionInfo internal = findOrCreateVersion( - StorageManager.UUID_PRIVATE_INTERNAL); - final VersionInfo external = findOrCreateVersion( - StorageManager.UUID_PRIMARY_PHYSICAL); - - internal.sdkVersion = parser.getAttributeInt(null, "internal", 0); - external.sdkVersion = parser.getAttributeInt(null, "external", 0); - internal.buildFingerprint = external.buildFingerprint = - XmlUtils.readStringAttribute(parser, "buildFingerprint"); - internal.fingerprint = external.fingerprint = - XmlUtils.readStringAttribute(parser, "fingerprint"); - - } else if (tagName.equals("database-version")) { - // Upgrade from older XML schema - final VersionInfo internal = findOrCreateVersion( - StorageManager.UUID_PRIVATE_INTERNAL); - final VersionInfo external = findOrCreateVersion( - StorageManager.UUID_PRIMARY_PHYSICAL); - - internal.databaseVersion = parser.getAttributeInt(null, "internal", 0); - external.databaseVersion = parser.getAttributeInt(null, "external", 0); - - } else if (tagName.equals("verifier")) { - final String deviceIdentity = parser.getAttributeValue(null, "device"); - try { - mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity); - } catch (IllegalArgumentException e) { - Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: " - + e.getMessage()); + + String tagName = parser.getName(); + if (tagName.equals("package")) { + readPackageLPw(parser, users, originalFirstInstallTimes); + } else if (tagName.equals("permissions")) { + mPermissions.readPermissions(parser); + } else if (tagName.equals("permission-trees")) { + mPermissions.readPermissionTrees(parser); + } else if (tagName.equals("shared-user")) { + readSharedUserLPw(parser, users); + } else if (tagName.equals("preferred-packages")) { + // no longer used. + } else if (tagName.equals("preferred-activities")) { + // Upgrading from old single-user implementation; + // these are the preferred activities for user 0. + readPreferredActivitiesLPw(parser, 0); + } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { + // TODO: check whether this is okay! as it is very + // similar to how preferred-activities are treated + readPersistentPreferredActivitiesLPw(parser, 0); + } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) { + // TODO: check whether this is okay! as it is very + // similar to how preferred-activities are treated + readCrossProfileIntentFiltersLPw(parser, 0); + } else if (tagName.equals(TAG_DEFAULT_BROWSER)) { + readDefaultAppsLPw(parser, 0); + } else if (tagName.equals("updated-package")) { + readDisabledSysPackageLPw(parser, users); + } else if (tagName.equals("renamed-package")) { + String nname = parser.getAttributeValue(null, "new"); + String oname = parser.getAttributeValue(null, "old"); + if (nname != null && oname != null) { + mRenamedPackages.put(nname, oname); + } + } else if (tagName.equals("last-platform-version")) { + // Upgrade from older XML schema + final VersionInfo internal = findOrCreateVersion( + StorageManager.UUID_PRIVATE_INTERNAL); + final VersionInfo external = findOrCreateVersion( + StorageManager.UUID_PRIMARY_PHYSICAL); + + internal.sdkVersion = parser.getAttributeInt(null, "internal", 0); + external.sdkVersion = parser.getAttributeInt(null, "external", 0); + internal.buildFingerprint = external.buildFingerprint = + XmlUtils.readStringAttribute(parser, "buildFingerprint"); + internal.fingerprint = external.fingerprint = + XmlUtils.readStringAttribute(parser, "fingerprint"); + + } else if (tagName.equals("database-version")) { + // Upgrade from older XML schema + final VersionInfo internal = findOrCreateVersion( + StorageManager.UUID_PRIVATE_INTERNAL); + final VersionInfo external = findOrCreateVersion( + StorageManager.UUID_PRIMARY_PHYSICAL); + + internal.databaseVersion = parser.getAttributeInt(null, "internal", 0); + external.databaseVersion = parser.getAttributeInt(null, "external", 0); + + } else if (tagName.equals("verifier")) { + final String deviceIdentity = parser.getAttributeValue(null, "device"); + try { + mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity); + } catch (IllegalArgumentException e) { + Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: " + + e.getMessage()); + } + } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) { + // No longer used. + } else if (tagName.equals("keyset-settings")) { + mKeySetManagerService.readKeySetsLPw(parser, + mKeySetRefs.untrackedStorage()); + } else if (TAG_VERSION.equals(tagName)) { + final String volumeUuid = XmlUtils.readStringAttribute(parser, + ATTR_VOLUME_UUID); + final VersionInfo ver = findOrCreateVersion(volumeUuid); + ver.sdkVersion = parser.getAttributeInt(null, ATTR_SDK_VERSION); + ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION); + ver.buildFingerprint = XmlUtils.readStringAttribute(parser, + ATTR_BUILD_FINGERPRINT); + ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT); + } else if (tagName.equals( + DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) { + mDomainVerificationManager.readSettings(computer, parser); + } else if (tagName.equals( + DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) { + mDomainVerificationManager.readLegacySettings(parser); + } else { + Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); } - } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) { - // No longer used. - } else if (tagName.equals("keyset-settings")) { - mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs.untrackedStorage()); - } else if (TAG_VERSION.equals(tagName)) { - final String volumeUuid = XmlUtils.readStringAttribute(parser, - ATTR_VOLUME_UUID); - final VersionInfo ver = findOrCreateVersion(volumeUuid); - ver.sdkVersion = parser.getAttributeInt(null, ATTR_SDK_VERSION); - ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION); - ver.buildFingerprint = XmlUtils.readStringAttribute(parser, - ATTR_BUILD_FINGERPRINT); - ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT); - } else if (tagName.equals(DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) { - mDomainVerificationManager.readSettings(computer, parser); - } else if (tagName.equals( - DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) { - mDomainVerificationManager.readLegacySettings(parser); - } else { - Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); } - } - str.close(); - } catch (IOException | XmlPullParserException e) { - mReadMessages.append("Error reading: " + e.toString()); - PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); + str.close(); + } catch (IOException | XmlPullParserException e) { + // Remove corrupted file and retry. + atomicFile.failRead(str, e); - // Remove corrupted file and retry. - Slog.e(TAG, - "Error reading package manager settings, removing " + file + " and retrying.", - e); - file.delete(); - - // Ignore the result to not mark this as a "first boot". - readSettingsLPw(computer, users, originalFirstInstallTimes); + // Ignore the result to not mark this as a "first boot". + readSettingsLPw(computer, users, originalFirstInstallTimes); + } } return true; @@ -4488,10 +4333,7 @@ public final class Settings implements Watchable, Snappable { mPreferredActivities.remove(userId); synchronized (mPackageRestrictionsLock) { - File file = getUserPackagesStateFile(userId); - file.delete(); - file = getUserPackagesStateBackupFile(userId); - file.delete(); + getUserPackagesStateFile(userId).delete(); mPendingAsyncPackageRestrictionsWrites.delete(userId); } @@ -5034,19 +4876,20 @@ public final class Settings implements Watchable, Snappable { } } pw.print(prefix); pw.print(" timeStamp="); - date.setTime(ps.getLastModifiedTime()); - pw.println(sdf.format(date)); + date.setTime(ps.getLastModifiedTime()); + pw.println(sdf.format(date)); pw.print(prefix); pw.print(" lastUpdateTime="); - date.setTime(ps.getLastUpdateTime()); - pw.println(sdf.format(date)); - if (ps.getInstallSource().mInstallerPackageName != null) { - pw.print(prefix); pw.print(" installerPackageName="); - pw.println(ps.getInstallSource().mInstallerPackageName); - } - if (ps.getInstallSource().mInstallerPackageUid != INVALID_UID) { - pw.print(prefix); pw.print(" installerPackageUid="); - pw.println(ps.getInstallSource().mInstallerPackageUid); - } + date.setTime(ps.getLastUpdateTime()); + pw.println(sdf.format(date)); + pw.print(prefix); pw.print(" installerPackageName="); + pw.println(ps.getInstallSource().mInstallerPackageName); + pw.print(prefix); pw.print(" installerPackageUid="); + pw.println(ps.getInstallSource().mInstallerPackageUid); + pw.print(prefix); pw.print(" initiatingPackageName="); + pw.println(ps.getInstallSource().mInitiatingPackageName); + pw.print(prefix); pw.print(" originatingPackageName="); + pw.println(ps.getInstallSource().mOriginatingPackageName); + if (ps.getInstallSource().mUpdateOwnerPackageName != null) { pw.print(prefix); pw.print(" updateOwnerPackageName="); pw.println(ps.getInstallSource().mUpdateOwnerPackageName); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 67639fbef124..28cb7f0b03a6 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -2048,6 +2048,9 @@ class ShortcutPackage extends ShortcutPackageItem { shortcutUser.getUserId(), fromBackup); // Don't use addShortcut(), we don't need to save the icon. ret.mShortcuts.put(si.getId(), si); + } catch (IOException e) { + // Don't ignore IO exceptions. + throw e; } catch (Exception e) { // b/246540168 malformed shortcuts should be ignored Slog.e(TAG, "Failed parsing shortcut.", e); diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java index e20330d562f6..8b118da1cdbe 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java @@ -27,6 +27,7 @@ import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.modules.utils.TypedXmlSerializer; +import com.android.server.security.FileIntegrity; import org.json.JSONException; import org.json.JSONObject; @@ -180,6 +181,12 @@ abstract class ShortcutPackageItem { os.flush(); file.finishWrite(os); + + try { + FileIntegrity.setUpFsVerity(path); + } catch (IOException e) { + Slog.e(TAG, "Failed to verity-protect " + path, e); + } } catch (XmlPullParserException | IOException e) { Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e); file.failWrite(os); diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 372b3bb8681b..20cb485434b0 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -119,7 +119,6 @@ import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.security.FileIntegrity; import com.android.server.uri.UriGrantsManagerInternal; import org.json.JSONArray; @@ -1070,57 +1069,38 @@ public class ShortcutService extends IShortcutService.Stub { } @VisibleForTesting - final File getUserFile(@UserIdInt int userId) { - return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES); - } - - @VisibleForTesting - final File getReserveCopyUserFile(@UserIdInt int userId) { - return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES_RESERVE_COPY); + final ResilientAtomicFile getUserFile(@UserIdInt int userId) { + File mainFile = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES); + File temporaryBackup = new File(injectUserDataPath(userId), + FILENAME_USER_PACKAGES + ".backup"); + File reserveCopy = new File(injectUserDataPath(userId), + FILENAME_USER_PACKAGES_RESERVE_COPY); + int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH; + return new ResilientAtomicFile(mainFile, temporaryBackup, reserveCopy, fileMode, + "user shortcut", null); } @GuardedBy("mLock") private void saveUserLocked(@UserIdInt int userId) { - final File path = getUserFile(userId); - if (DEBUG || DEBUG_REBOOT) { - Slog.d(TAG, "Saving to " + path); - } - - final File reservePath = getReserveCopyUserFile(userId); - reservePath.delete(); - - path.getParentFile().mkdirs(); - final AtomicFile file = new AtomicFile(path); - FileOutputStream os = null; - try { - os = file.startWrite(); - - saveUserInternalLocked(userId, os, /* forBackup= */ false); + try (ResilientAtomicFile file = getUserFile(userId)) { + FileOutputStream os = null; + try { + if (DEBUG || DEBUG_REBOOT) { + Slog.d(TAG, "Saving to " + file); + } - file.finishWrite(os); + os = file.startWrite(); - // Remove all dangling bitmap files. - cleanupDanglingBitmapDirectoriesLocked(userId); - } catch (XmlPullParserException | IOException e) { - Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e); - file.failWrite(os); - } + saveUserInternalLocked(userId, os, /* forBackup= */ false); - // Store the reserve copy of the file. - try (FileInputStream in = new FileInputStream(path); - FileOutputStream out = new FileOutputStream(reservePath)) { - FileUtils.copy(in, out); - FileUtils.sync(out); - } catch (IOException e) { - Slog.e(TAG, "Failed to write reserve copy: " + path, e); - } + file.finishWrite(os); - // Protect both primary and reserve copy with fs-verity. - try { - FileIntegrity.setUpFsVerity(path); - FileIntegrity.setUpFsVerity(reservePath); - } catch (IOException e) { - Slog.e(TAG, "Failed to verity-protect", e); + // Remove all dangling bitmap files. + cleanupDanglingBitmapDirectoriesLocked(userId); + } catch (XmlPullParserException | IOException e) { + Slog.e(TAG, "Failed to write to file " + file, e); + file.failWrite(os); + } } getUserShortcutsLocked(userId).logSharingShortcutStats(mMetricsLogger); @@ -1157,29 +1137,26 @@ public class ShortcutService extends IShortcutService.Stub { @Nullable private ShortcutUser loadUserLocked(@UserIdInt int userId) { - final File path = getUserFile(userId); - if (DEBUG || DEBUG_REBOOT) { - Slog.d(TAG, "Loading from " + path); - } - - try (FileInputStream in = new AtomicFile(path).openRead()) { - return loadUserInternal(userId, in, /* forBackup= */ false); - } catch (FileNotFoundException e) { - if (DEBUG || DEBUG_REBOOT) { - Slog.d(TAG, "Not found " + path); - } - } catch (Exception e) { - final File reservePath = getReserveCopyUserFile(userId); - Slog.e(TAG, "Reading from reserve copy: " + reservePath, e); - try (FileInputStream in = new AtomicFile(reservePath).openRead()) { + try (ResilientAtomicFile file = getUserFile(userId)) { + FileInputStream in = null; + try { + if (DEBUG || DEBUG_REBOOT) { + Slog.d(TAG, "Loading from " + file); + } + in = file.openRead(); + if (in == null) { + if (DEBUG || DEBUG_REBOOT) { + Slog.d(TAG, "Not found " + file); + } + return null; + } return loadUserInternal(userId, in, /* forBackup= */ false); - } catch (Exception exceptionReadingReserveFile) { - Slog.e(TAG, "Failed to read reserve copy: " + reservePath, - exceptionReadingReserveFile); + } catch (Exception e) { + // Remove corrupted file and retry. + file.failRead(in, e); + return loadUserLocked(userId); } - Slog.e(TAG, "Failed to read file " + path, e); } - return null; } private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is, diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index 9ef1bba16351..b4d467f96091 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -64,12 +64,11 @@ public abstract class UserManagerInternal { }) public @interface UserAssignmentResult {} - // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively. - @Keep public static final int USER_START_MODE_FOREGROUND = 1; - @Keep public static final int USER_START_MODE_BACKGROUND = 2; - @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3; - private static final String PREFIX_USER_START_MODE = "USER_START_MODE_"; + + /** + * Type used to indicate how a user started. + */ @IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = { USER_START_MODE_FOREGROUND, USER_START_MODE_BACKGROUND, @@ -77,6 +76,32 @@ public abstract class UserManagerInternal { }) public @interface UserStartMode {} + // TODO(b/248408342): Move keep annotations below to the method referencing these fields + // reflectively. + + /** (Full) user started on foreground (a.k.a. "current user"). */ + @Keep public static final int USER_START_MODE_FOREGROUND = 1; + + /** + * User (full or profile) started on background and is + * {@link UserManager#isUserVisible() invisible}. + * + * <p>This is the "traditional" way of starting a background user, and can be used to start + * profiles as well, although starting an invisible profile is not common from the System UI + * (it could be done through APIs or adb, though). + */ + @Keep public static final int USER_START_MODE_BACKGROUND = 2; + + /** + * User (full or profile) started on background and is + * {@link UserManager#isUserVisible() visible}. + * + * <p>This is the "traditional" way of starting a profile (i.e., when the profile of the current + * user is the current foreground user), but it can also be used to start a full user associated + * with a display (which is the case on automotives with passenger displays). + */ + @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3; + public interface UserRestrictionsListener { /** * Called when a user restriction changes. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 2b08a2c0a31b..2f98d3485d90 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2049,6 +2049,27 @@ public class UserManagerService extends IUserManager.Stub { + "permission to: check " + name); } + /** + * Enforces that the calling user is in the same profile group as {@code userId} or that only + * the system UID or root's UID or apps that have the + * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or + * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} or + * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS} + * can make certain calls to the UserManager. + * + * @param userId the user's id + * @param name used as message if SecurityException is thrown + * @throws SecurityException if the caller lacks the required permissions. + */ + private void checkQueryOrCreateUsersPermissionIfCallerInOtherProfileGroup( + @UserIdInt int userId, String name) { + final int callingUserId = UserHandle.getCallingUserId(); + if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId)) { + return; + } + checkQueryOrCreateUsersPermission(name); + } + @Override public boolean isDemoUser(@UserIdInt int userId) { final int callingUserId = UserHandle.getCallingUserId(); @@ -2063,6 +2084,15 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public boolean isAdminUser(@UserIdInt int userId) { + checkQueryOrCreateUsersPermissionIfCallerInOtherProfileGroup(userId, "isAdminUser"); + synchronized (mUsersLock) { + final UserInfo userInfo = getUserInfoLU(userId); + return userInfo != null && userInfo.isAdmin(); + } + } + + @Override public boolean isPreCreated(@UserIdInt int userId) { checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isPreCreated"); synchronized (mUsersLock) { @@ -3605,6 +3635,13 @@ public class UserManagerService extends IUserManager.Stub { } finally { IoUtils.closeQuietly(fis); } + + synchronized (mUsersLock) { + if (mUsers.size() == 0) { + Slog.e(LOG_TAG, "mUsers is empty, fallback to single user"); + fallbackToSingleUserLP(); + } + } } /** diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java index 3f7502bfa613..f87f50add5be 100644 --- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java +++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java @@ -42,6 +42,7 @@ import android.util.Dumpable; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.IntArray; +import android.util.Log; import android.util.SparseIntArray; import android.view.Display; @@ -55,6 +56,8 @@ import com.android.server.pm.UserManagerInternal.UserVisibilityListener; import com.android.server.utils.Slogf; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -77,11 +80,11 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public final class UserVisibilityMediator implements Dumpable { - private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE - private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE - private static final String TAG = UserVisibilityMediator.class.getSimpleName(); + private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE + private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_"; public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1; public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2; @@ -98,7 +101,7 @@ public final class UserVisibilityMediator implements Dumpable { }) public @interface SecondaryDisplayMappingStatus {} - // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices + // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices @VisibleForTesting static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM; @@ -132,10 +135,23 @@ public final class UserVisibilityMediator implements Dumpable { private final SparseIntArray mExtraDisplaysAssignedToUsers; /** - * Mapping from each started user to its profile group. + * Mapping of each user that started visible (key) to its profile group id (value). + * + * <p>It's used to determine not just if the user is visible, but also + * {@link #isProfile(int, int) if it's a profile}. + */ + @GuardedBy("mLock") + private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray(); + + /** + * List of profiles that have explicitly started invisible. + * + * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we + * don't care about autoboxing. */ @GuardedBy("mLock") - private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray(); + @Nullable + private final List<Integer> mStartedInvisibleProfileUserIds; /** * Handler user to call listeners @@ -164,9 +180,14 @@ public final class UserVisibilityMediator implements Dumpable { mUsersAssignedToDisplayOnStart = null; mExtraDisplaysAssignedToUsers = null; } + mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null; mHandler = handler; - // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices - mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID); + // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices + mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID); + + if (DBG) { + Slogf.i(TAG, "UserVisibilityMediator created with DBG on"); + } } /** @@ -177,6 +198,8 @@ public final class UserVisibilityMediator implements Dumpable { int displayId) { Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d", userId); + validateUserStartMode(userStartMode); + // This method needs to perform 4 actions: // // 1. Check if the user can be started given the provided arguments @@ -224,14 +247,29 @@ public final class UserVisibilityMediator implements Dumpable { visibleUsersBefore = getVisibleUsers(); - // Set current user / profiles state - if (userStartMode == USER_START_MODE_FOREGROUND) { - mCurrentUserId = userId; - } - if (DBG) { - Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId); + // Set current user / started users state + switch (userStartMode) { + case USER_START_MODE_FOREGROUND: + mCurrentUserId = userId; + // Fallthrough + case USER_START_MODE_BACKGROUND_VISIBLE: + if (DBG) { + Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)", + userId, profileGroupId); + } + mStartedVisibleProfileGroupIds.put(userId, profileGroupId); + break; + case USER_START_MODE_BACKGROUND: + if (mStartedInvisibleProfileUserIds != null + && isProfile(userId, profileGroupId)) { + Slogf.d(TAG, "adding user %d to list of invisible profiles", userId); + mStartedInvisibleProfileUserIds.add(userId); + } + break; + default: + Slogf.wtf(TAG, "invalid userStartMode passed to assignUserToDisplayOnStart: " + + "%d", userStartMode); } - mStartedProfileGroupIds.put(userId, profileGroupId); // Set user / display state switch (mappingResult) { @@ -297,38 +335,44 @@ public final class UserVisibilityMediator implements Dumpable { boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; if (displayId != DEFAULT_DISPLAY) { if (foreground) { - Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start " + Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start " + "foreground user on secondary display", userId, profileGroupId, - foreground, displayId); + userStartModeToString(userStartMode), displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } if (!mVisibleBackgroundUsersEnabled) { - Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: called on " + Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on " + "device that doesn't support multiple users on multiple displays", - userId, profileGroupId, foreground, displayId); + userId, profileGroupId, userStartModeToString(userStartMode), displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } } if (isProfile(userId, profileGroupId)) { if (displayId != DEFAULT_DISPLAY) { - Slogf.w(TAG, "canStartUserLocked(%d, %d, %b, %d) failed: cannot start profile user " - + "on secondary display", userId, profileGroupId, foreground, - displayId); + Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user " + + "on secondary display", userId, profileGroupId, + userStartModeToString(userStartMode), displayId); return USER_ASSIGNMENT_RESULT_FAILURE; } - if (foreground) { - Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in " - + "foreground", userId, profileGroupId, foreground, displayId); - return USER_ASSIGNMENT_RESULT_FAILURE; - } else { - boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId); - if (DBG) { - Slogf.d(TAG, "parent visible on display: %b", isParentVisibleOnDisplay); - } - return isParentVisibleOnDisplay - ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE - : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; + switch (userStartMode) { + case USER_START_MODE_FOREGROUND: + Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in " + + "foreground", userId, profileGroupId, + userStartModeToString(userStartMode), displayId); + return USER_ASSIGNMENT_RESULT_FAILURE; + case USER_START_MODE_BACKGROUND_VISIBLE: + boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId); + if (!isParentVisibleOnDisplay) { + Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot" + + " start profile user visible when its parent is not visible in " + + "that display", userId, profileGroupId, + userStartModeToString(userStartMode), displayId); + return USER_ASSIGNMENT_RESULT_FAILURE; + } + return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; + case USER_START_MODE_BACKGROUND: + return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; } } else if (mUsersAssignedToDisplayOnStart != null && isUserAssignedToDisplayOnStartLocked(userId, displayId)) { @@ -353,8 +397,9 @@ public final class UserVisibilityMediator implements Dumpable { if (mVisibleBackgroundUserOnDefaultDisplayAllowed && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) { int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY); - if (userStartedOnDefaultDisplay != USER_NULL) { - Slogf.w(TAG, "getUserVisibilityOnStartLocked(): cannot start user %d visible on" + if (userStartedOnDefaultDisplay != USER_NULL + && userStartedOnDefaultDisplay != profileGroupId) { + Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on" + " default display because user %d already did so", userId, userStartedOnDefaultDisplay); return SECONDARY_DISPLAY_MAPPING_FAILED; @@ -468,7 +513,7 @@ public final class UserVisibilityMediator implements Dumpable { userId, displayId); return false; } - if (isStartedProfile(userId)) { + if (isStartedVisibleProfileLocked(userId)) { Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile", userId, displayId); return false; @@ -556,10 +601,14 @@ public final class UserVisibilityMediator implements Dumpable { @GuardedBy("mLock") private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) { if (DBG) { - Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId, - mStartedProfileGroupIds); + Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId, + mStartedVisibleProfileGroupIds); + } + mStartedVisibleProfileGroupIds.delete(userId); + if (mStartedInvisibleProfileUserIds != null) { + Slogf.d(TAG, "Removing %d from list of invisible profiles", userId); + mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId)); } - mStartedProfileGroupIds.delete(userId); if (!mVisibleBackgroundUsersEnabled) { // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as @@ -589,7 +638,8 @@ public final class UserVisibilityMediator implements Dumpable { * See {@link UserManagerInternal#isUserVisible(int)}. */ public boolean isUserVisible(@UserIdInt int userId) { - // First check current foreground user and their profiles (on main display) + // For optimization (as most devices don't support visible background users), check for + // current foreground user and their profiles first if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) { if (VERBOSE) { Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId); @@ -598,19 +648,31 @@ public final class UserVisibilityMediator implements Dumpable { } if (!mVisibleBackgroundUsersEnabled) { - if (DBG) { - Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when" + if (VERBOSE) { + Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when" + " device doesn't support visible background users", userId); } return false; } - boolean visible; + synchronized (mLock) { - visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0; + int profileGroupId; + synchronized (mLock) { + profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); + } + if (isProfile(userId, profileGroupId)) { + return isUserAssignedToDisplayOnStartLocked(profileGroupId); + } + return isUserAssignedToDisplayOnStartLocked(userId); } - if (DBG) { - Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible); + } + + @GuardedBy("mLock") + private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) { + boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0; + if (VERBOSE) { + Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible); } return visible; } @@ -640,7 +702,8 @@ public final class UserVisibilityMediator implements Dumpable { return false; } - // Current user is always visible on: + // For optimization (as most devices don't support visible background users), check for + // current user and profile first. Current user is always visible on: // - Default display // - Secondary displays when device doesn't support visible bg users // - Or when explicitly added (which is checked below) @@ -662,14 +725,26 @@ public final class UserVisibilityMediator implements Dumpable { } synchronized (mLock) { - if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) { - // User assigned to display on start - return true; + int profileGroupId; + synchronized (mLock) { + profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); } + if (isProfile(userId, profileGroupId)) { + return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId); + } + return isFullUserVisibleOnBackgroundLocked(userId, displayId); + } + } - // Check for extra display assignment - return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId; + // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that + @GuardedBy("mLock") + private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) { + if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) { + // User assigned to display on start + return true; } + // Check for extra display assignment + return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId; } /** @@ -737,7 +812,7 @@ public final class UserVisibilityMediator implements Dumpable { continue; } int userId = mUsersAssignedToDisplayOnStart.keyAt(i); - if (!isStartedProfile(userId)) { + if (!isStartedVisibleProfileLocked(userId)) { return userId; } else if (DBG) { Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's " @@ -770,8 +845,8 @@ public final class UserVisibilityMediator implements Dumpable { // number of users is too small, the gain is probably not worth the increase on complexity. IntArray visibleUsers = new IntArray(); synchronized (mLock) { - for (int i = 0; i < mStartedProfileGroupIds.size(); i++) { - int userId = mStartedProfileGroupIds.keyAt(i); + for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) { + int userId = mStartedVisibleProfileGroupIds.keyAt(i); if (isUserVisible(userId)) { visibleUsers.add(userId); } @@ -804,7 +879,7 @@ public final class UserVisibilityMediator implements Dumpable { } } - // TODO(b/242195409): remove this method if not needed anymore + // TODO(b/266158156): remove this method if not needed anymore /** * Nofify all listeners that the system user visibility changed. */ @@ -866,6 +941,9 @@ public final class UserVisibilityMediator implements Dumpable { ipw.println("UserVisibilityMediator"); ipw.increaseIndent(); + ipw.print("DBG: "); + ipw.println(DBG); + synchronized (mLock) { ipw.print("Current user id: "); ipw.println(mCurrentUserId); @@ -873,8 +951,12 @@ public final class UserVisibilityMediator implements Dumpable { ipw.print("Visible users: "); ipw.println(getVisibleUsers()); - dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group", - "u", "pg"); + dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds, + "started visible user / profile group", "u", "pg"); + if (mStartedInvisibleProfileUserIds != null) { + ipw.print("Profiles started invisible: "); + ipw.println(mStartedInvisibleProfileUserIds); + } ipw.print("Supports visible background users on displays: "); ipw.println(mVisibleBackgroundUsersEnabled); @@ -982,22 +1064,25 @@ public final class UserVisibilityMediator implements Dumpable { if (mCurrentUserId == userId) { return true; } - return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId; + return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) + == mCurrentUserId; } } - private boolean isStartedProfile(@UserIdInt int userId) { - int profileGroupId; - synchronized (mLock) { - profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); - } + @GuardedBy("mLock") + private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) { + int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); return isProfile(userId, profileGroupId); } - private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) { - synchronized (mLock) { - return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID); + private void validateUserStartMode(@UserStartMode int userStartMode) { + switch (userStartMode) { + case USER_START_MODE_FOREGROUND: + case USER_START_MODE_BACKGROUND: + case USER_START_MODE_BACKGROUND_VISIBLE: + return; } + throw new IllegalArgumentException("Invalid user start mode: " + userStartMode); } private static String secondaryDisplayMappingStatusToString( diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 45dc49dba2ca..37a59da33ad8 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2977,7 +2977,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } break; case KeyEvent.KEYCODE_H: - if (down && event.isMetaPressed()) { + if (event.isMetaPressed()) { return handleHomeShortcuts(displayId, focusedToken, event); } break; @@ -3018,11 +3018,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) { enterStageSplitFromRunningApp(true /* leftOrTop */); return key_consumed; - } else if (!down && event.isMetaPressed()) { - boolean backKeyHandled = backKeyPress(); - if (backKeyHandled) { - return key_consumed; - } } break; case KeyEvent.KEYCODE_DPAD_RIGHT: @@ -3031,14 +3026,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return key_consumed; } break; - case KeyEvent.KEYCODE_GRAVE: - if (!down && event.isMetaPressed()) { - boolean backKeyHandled = backKeyPress(); - if (backKeyHandled) { - return key_consumed; - } - } - break; case KeyEvent.KEYCODE_SLASH: if (down && repeatCount == 0 && event.isMetaPressed() && !keyguardOn) { toggleKeyboardShortcutsMenu(event.getDeviceId()); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index bf8cbeac30c8..2e8a150f2b6d 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -5693,6 +5693,7 @@ public final class PowerManagerService extends SystemService } if (eventTime > now) { + Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); throw new IllegalArgumentException("event time must not be in the future"); } @@ -5708,7 +5709,9 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void wakeUp(long eventTime, @WakeReason int reason, String details, String opPackageName) { - if (eventTime > mClock.uptimeMillis()) { + final long now = mClock.uptimeMillis(); + if (eventTime > now) { + Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); throw new IllegalArgumentException("event time must not be in the future"); } @@ -5760,7 +5763,9 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void nap(long eventTime) { - if (eventTime > mClock.uptimeMillis()) { + final long now = mClock.uptimeMillis(); + if (eventTime > now) { + Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); throw new IllegalArgumentException("event time must not be in the future"); } @@ -6525,7 +6530,9 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void boostScreenBrightness(long eventTime) { + final long now = mClock.uptimeMillis(); if (eventTime > mClock.uptimeMillis()) { + Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); throw new IllegalArgumentException("event time must not be in the future"); } @@ -6684,7 +6691,9 @@ public final class PowerManagerService extends SystemService @RequiresPermission(android.Manifest.permission.DEVICE_POWER) private void goToSleepInternal(IntArray groupIds, long eventTime, int reason, int flags) { - if (eventTime > mClock.uptimeMillis()) { + final long now = mClock.uptimeMillis(); + if (eventTime > now) { + Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); throw new IllegalArgumentException("event time must not be in the future"); } 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 f11c864edba0..bc23020e8dbe 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -12688,8 +12688,8 @@ public class BatteryStatsImpl extends BatteryStats { energy = info.getControllerEnergyUsed(); if (!info.getUidTraffic().isEmpty()) { for (UidTraffic traffic : info.getUidTraffic()) { - uidRxBytes.incrementValue(traffic.getUid(), traffic.getRxBytes()); - uidTxBytes.incrementValue(traffic.getUid(), traffic.getTxBytes()); + uidRxBytes.put(traffic.getUid(), traffic.getRxBytes()); + uidTxBytes.put(traffic.getUid(), traffic.getTxBytes()); } } } diff --git a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java index 54f3476d3b86..706aedcbba7b 100644 --- a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java +++ b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java @@ -18,6 +18,7 @@ package com.android.server.power.stats; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN; +import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI; import android.content.Context; import android.os.Handler; @@ -49,6 +50,7 @@ public class CpuWakeupStats { private static final String TAG = "CpuWakeupStats"; private static final String SUBSYSTEM_ALARM_STRING = "Alarm"; + private static final String SUBSYSTEM_ALARM_WIFI = "Wifi"; @VisibleForTesting static final long WAKEUP_RETENTION_MS = 3 * 24 * 60 * 60_000; // 3 days. @VisibleForTesting @@ -74,6 +76,8 @@ public class CpuWakeupStats { switch (subsystem) { case CPU_WAKEUP_SUBSYSTEM_ALARM: return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__ALARM; + case CPU_WAKEUP_SUBSYSTEM_WIFI: + return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__WIFI; } return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__UNKNOWN; } @@ -122,7 +126,10 @@ public class CpuWakeupStats { /** Notes a wakeup reason as reported by SuspendControlService to battery stats. */ public synchronized void noteWakeupTimeAndReason(long elapsedRealtime, long uptime, String rawReason) { - final Wakeup parsedWakeup = new Wakeup(rawReason, elapsedRealtime, uptime); + final Wakeup parsedWakeup = Wakeup.parseWakeup(rawReason, elapsedRealtime, uptime); + if (parsedWakeup == null) { + return; + } mWakeupEvents.put(elapsedRealtime, parsedWakeup); attemptAttributionFor(parsedWakeup); // Assuming that wakeups always arrive in monotonically increasing elapsedRealtime order, @@ -425,6 +432,8 @@ public class CpuWakeupStats { switch (rawSubsystem) { case SUBSYSTEM_ALARM_STRING: return CPU_WAKEUP_SUBSYSTEM_ALARM; + case SUBSYSTEM_ALARM_WIFI: + return CPU_WAKEUP_SUBSYSTEM_WIFI; } return CPU_WAKEUP_SUBSYSTEM_UNKNOWN; } @@ -433,6 +442,8 @@ public class CpuWakeupStats { switch (subsystem) { case CPU_WAKEUP_SUBSYSTEM_ALARM: return SUBSYSTEM_ALARM_STRING; + case CPU_WAKEUP_SUBSYSTEM_WIFI: + return SUBSYSTEM_ALARM_WIFI; case CPU_WAKEUP_SUBSYSTEM_UNKNOWN: return "Unknown"; } @@ -443,28 +454,25 @@ public class CpuWakeupStats { private static final String PARSER_TAG = "CpuWakeupStats.Wakeup"; private static final String ABORT_REASON_PREFIX = "Abort"; private static final Pattern sIrqPattern = Pattern.compile("^(\\d+)\\s+(\\S+)"); - - String mRawReason; long mElapsedMillis; long mUptimeMillis; IrqDevice[] mDevices; - Wakeup(String rawReason, long elapsedMillis, long uptimeMillis) { - mRawReason = rawReason; + private Wakeup(IrqDevice[] devices, long elapsedMillis, long uptimeMillis) { mElapsedMillis = elapsedMillis; mUptimeMillis = uptimeMillis; - mDevices = parseIrqDevices(rawReason); + mDevices = devices; } - private static IrqDevice[] parseIrqDevices(String rawReason) { + static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis) { final String[] components = rawReason.split(":"); if (ArrayUtils.isEmpty(components) || components[0].startsWith(ABORT_REASON_PREFIX)) { - // We don't support parsing aborts yet. + // Accounting of aborts is not supported yet. return null; } int parsedDeviceCount = 0; - IrqDevice[] parsedDevices = new IrqDevice[components.length]; + final IrqDevice[] parsedDevices = new IrqDevice[components.length]; for (String component : components) { final Matcher matcher = sIrqPattern.matcher(component.trim()); @@ -482,14 +490,17 @@ public class CpuWakeupStats { parsedDevices[parsedDeviceCount++] = new IrqDevice(line, device); } } - return (parsedDeviceCount > 0) ? Arrays.copyOf(parsedDevices, parsedDeviceCount) : null; + if (parsedDeviceCount == 0) { + return null; + } + return new Wakeup(Arrays.copyOf(parsedDevices, parsedDeviceCount), elapsedMillis, + uptimeMillis); } @Override public String toString() { return "Wakeup{" - + "mRawReason='" + mRawReason + '\'' - + ", mElapsedMillis=" + mElapsedMillis + + "mElapsedMillis=" + mElapsedMillis + ", mUptimeMillis=" + TimeUtils.formatDuration(mUptimeMillis) + ", mDevices=" + Arrays.toString(mDevices) + '}'; @@ -506,7 +517,7 @@ public class CpuWakeupStats { @Override public String toString() { - return "IrqDevice{" + "mLine=" + mLine + ", mDevice='" + mDevice + '\'' + '}'; + return "IrqDevice{" + "mLine=" + mLine + ", mDevice=\'" + mDevice + '\'' + '}'; } } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index ac03808deba1..c9eef387eeb2 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -923,6 +923,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken); mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId, null /* options */); + mWindowManagerInternal.setWallpaperShowWhenLocked( + mToken, (wallpaper.mWhich & FLAG_LOCK) != 0); final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId); try { @@ -945,7 +947,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */, mDisplayId); try { - connection.mService.detach(mToken); + if (connection.mService != null) { + connection.mService.detach(mToken); + } } catch (RemoteException e) { Slog.w(TAG, "connection.mService.destroy() threw a RemoteException"); } @@ -1413,12 +1417,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub try { if (connector.mEngine != null) { connector.mEngine.setWallpaperFlags(which); + mWindowManagerInternal.setWallpaperShowWhenLocked( + connector.mToken, (which & FLAG_LOCK) != 0); } } catch (RemoteException e) { Slog.e(TAG, "Failed to update wallpaper engine flags", e); } - } - ); + }); } } diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 01e9522044a1..d108f0de5d15 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -1714,4 +1714,20 @@ class ActivityClientController extends IActivityClientController.Stub { } } } + + /** + * Returns {@code true} if the activity was explicitly requested to be launched in its + * current TaskFragment. + * + * @see ActivityRecord#mRequestedLaunchingTaskFragmentToken + */ + public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken, + IBinder taskFragmentToken) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken); + if (r == null) return false; + + return r.mRequestedLaunchingTaskFragmentToken == taskFragmentToken; + } + } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e62d30533d3d..37e4890bad0e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -565,6 +565,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A volatile boolean inHistory; final ActivityTaskSupervisor mTaskSupervisor; final RootWindowContainer mRootWindowContainer; + // The token of the TaskFragment that this activity was requested to be launched into. + IBinder mRequestedLaunchingTaskFragmentToken; // Tracking splash screen status from previous activity boolean mSplashScreenStyleSolidColor = false; @@ -1605,6 +1607,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (oldParent != null) { oldParent.cleanUpActivityReferences(this); + // Clear the state as this activity is removed from its old parent. + mRequestedLaunchingTaskFragmentToken = null; } if (newParent != null) { @@ -5224,8 +5228,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true; } - @VisibleForTesting - void setVisibility(boolean visible, boolean deferHidingClient) { + private void setVisibility(boolean visible, boolean deferHidingClient) { final AppTransition appTransition = getDisplayContent().mAppTransition; // Don't set visibility to false if we were already not visible. This prevents WM from @@ -7933,7 +7936,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } return getTask().getConfiguration().smallestScreenWidthDp - >= mAtmService.mLargeScreenSmallestScreenWidthDp; + >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; } /** @@ -8080,11 +8083,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } } - // Activity should be resizable if the task is. - final boolean isResizeable = task != null - ? task.isResizeable() || isResizeable() - : isResizeable(); - return !isResizeable && (info.isFixedOrientation() || hasFixedAspectRatio()) + return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio()) // The configuration of non-standard type should be enforced by system. // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is // added to a task, but this function is called when resolving the launch params, at diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index ac07248d15f2..88d10866d776 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -3036,6 +3036,8 @@ class ActivityStarter { int embeddingCheckResult = canEmbedActivity(mInTaskFragment, mStartActivity, task); if (embeddingCheckResult == EMBEDDING_ALLOWED) { newParent = mInTaskFragment; + mStartActivity.mRequestedLaunchingTaskFragmentToken = + mInTaskFragment.getFragmentToken(); } else { // Start mStartActivity to task instead if it can't be embedded to mInTaskFragment. sendCanNotEmbedActivityError(mInTaskFragment, embeddingCheckResult); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 7d478b3c7ca5..923ca794e840 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -609,7 +609,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * Whether the device supports non-resizable in multi windowing modes. * -1: The device doesn't support non-resizable in multi windowing modes. * 0: The device supports non-resizable in multi windowing modes only if this is a large - * screen (smallest width >= {@link #mLargeScreenSmallestScreenWidthDp}). + * screen (smallest width >= {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}). * 1: The device always supports non-resizable in multi windowing modes. */ int mSupportsNonResizableMultiWindow; @@ -619,7 +619,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * windowing modes. * -1: The device ignores activity min width/height when determining if it can be shown in multi * windowing modes. - * 0: If it is a small screen (smallest width < {@link #mLargeScreenSmallestScreenWidthDp}), + * 0: If it is a small screen (smallest width < + * {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}), * the device compares the activity min width/height with the min multi windowing modes * dimensions {@link #mMinPercentageMultiWindowSupportHeight} the device supports to * determine whether the activity can be shown in multi windowing modes @@ -647,13 +648,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ float mMinPercentageMultiWindowSupportWidth; - /** - * If the display {@link Configuration#smallestScreenWidthDp} is greater or equal to this value, - * we will treat it as a large screen device, which will have some multi window features enabled - * by default. - */ - int mLargeScreenSmallestScreenWidthDp; - final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>(); // VR Vr2d Display Id. @@ -914,8 +908,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { com.android.internal.R.dimen.config_minPercentageMultiWindowSupportHeight); final float minPercentageMultiWindowSupportWidth = mContext.getResources().getFloat( com.android.internal.R.dimen.config_minPercentageMultiWindowSupportWidth); - final int largeScreenSmallestScreenWidthDp = mContext.getResources().getInteger( - com.android.internal.R.integer.config_largeScreenSmallestScreenWidthDp); // Transfer any global setting for forcing RTL layout, into a System Property DisplayProperties.debug_force_rtl(forceRtl); @@ -934,7 +926,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRespectsActivityMinWidthHeightMultiWindow = respectsActivityMinWidthHeightMultiWindow; mMinPercentageMultiWindowSupportHeight = minPercentageMultiWindowSupportHeight; mMinPercentageMultiWindowSupportWidth = minPercentageMultiWindowSupportWidth; - mLargeScreenSmallestScreenWidthDp = largeScreenSmallestScreenWidthDp; final boolean multiWindowFormEnabled = freeformWindowManagement || supportsSplitScreenMultiWindow || supportsPictureInPicture diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index df471c56fec9..710c4af56dd1 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -1729,14 +1729,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } if (ActivitySecurityModelFeatureFlags.shouldShowToast(callingUid)) { - Toast toast = Toast.makeText(mService.mContext, + UiThread.getHandler().post(() -> Toast.makeText(mService.mContext, (ActivitySecurityModelFeatureFlags.DOC_LINK - + (restrictActivitySwitch - ? "returned home due to " - : "would return home due to ") - + callingLabel), - Toast.LENGTH_LONG); - UiThread.getHandler().post(toast::show); + + (restrictActivitySwitch ? " returned home due to " + : " would return home due to ") + + callingLabel), Toast.LENGTH_LONG).show()); } // If the activity switch should be restricted, return home rather than the diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index f73c68a42ec7..939cf1ae471b 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -888,8 +888,11 @@ public class AppTransition implements Dump { } else { int animAttr = mapOpenCloseTransitTypes(transit, enter); if (animAttr != 0) { - a = loadCustomActivityAnimation(animAttr, enter, container); - if (a == null) { + final CustomAppTransition customAppTransition = + getCustomAppTransition(animAttr, container); + if (customAppTransition != null) { + a = loadCustomActivityAnimation(customAppTransition, enter, container); + } else { if (canCustomizeAppTransition) { a = loadAnimationAttr(lp, animAttr, transit); } else { @@ -911,7 +914,7 @@ public class AppTransition implements Dump { return a; } - Animation loadCustomActivityAnimation(int animAttr, boolean enter, WindowContainer container) { + CustomAppTransition getCustomAppTransition(int animAttr, WindowContainer container) { ActivityRecord customAnimationSource = container.asActivityRecord(); if (customAnimationSource == null) { return null; @@ -927,31 +930,28 @@ public class AppTransition implements Dump { return null; } } - final CustomAppTransition custom; switch (animAttr) { case WindowAnimation_activityOpenEnterAnimation: case WindowAnimation_activityOpenExitAnimation: - custom = customAnimationSource.getCustomAnimation(true /* open */); - break; + return customAnimationSource.getCustomAnimation(true /* open */); case WindowAnimation_activityCloseEnterAnimation: case WindowAnimation_activityCloseExitAnimation: - custom = customAnimationSource.getCustomAnimation(false /* open */); - break; - default: - return null; - } - if (custom != null) { - final Animation a = mTransitionAnimation.loadAppTransitionAnimation( - customAnimationSource.packageName, enter - ? custom.mEnterAnim : custom.mExitAnim); - if (a != null && custom.mBackgroundColor != 0) { - a.setBackdropColor(custom.mBackgroundColor); - a.setShowBackdrop(true); - } - return a; + return customAnimationSource.getCustomAnimation(false /* open */); } return null; } + private Animation loadCustomActivityAnimation(@NonNull CustomAppTransition custom, + boolean enter, WindowContainer container) { + final ActivityRecord customAnimationSource = container.asActivityRecord(); + final Animation a = mTransitionAnimation.loadAppTransitionAnimation( + customAnimationSource.packageName, enter + ? custom.mEnterAnim : custom.mExitAnim); + if (a != null && custom.mBackgroundColor != 0) { + a.setBackdropColor(custom.mBackgroundColor); + a.setShowBackdrop(true); + } + return a; + } int getAppRootTaskClipMode() { return mNextAppTransitionRequests.contains(TRANSIT_RELAUNCH) diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java index 0dc6e0ff1054..5c9c81300e0d 100644 --- a/services/core/java/com/android/server/wm/AsyncRotationController.java +++ b/services/core/java/com/android/server/wm/AsyncRotationController.java @@ -364,6 +364,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume /** Hides the window immediately until it is drawn in new rotation. */ void hideImmediately(WindowToken windowToken) { + if (isTargetToken(windowToken)) return; final boolean original = mHideImmediately; mHideImmediately = true; final Operation op = new Operation(Operation.ACTION_FADE); diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index a229fc5b00d3..2d45dc20c963 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -75,6 +75,11 @@ class BackNavigationController { private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); + // This will be set if the back navigation is in progress and the current transition is still + // running. The pending animation builder will do the animation stuff includes creating leashes, + // re-parenting leashes and set launch behind, etc. Will be handled when transition finished. + private AnimationHandler.ScheduleAnimationBuilder mPendingAnimationBuilder; + /** * true if the back predictability feature is enabled */ @@ -305,25 +310,26 @@ class BackNavigationController { || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) && adapter != null; - // Only prepare animation if no leash has been created (no animation is running). - // TODO(b/241808055): Cancel animation when preparing back animation. - if (prepareAnimation - && (removedWindowContainer.hasCommittedReparentToAnimationLeash() - || removedWindowContainer.mTransitionController.inTransition())) { - Slog.w(TAG, "Can't prepare back animation due to another animation is running."); - prepareAnimation = false; - } - if (prepareAnimation) { - mPendingAnimation = mAnimationHandler.scheduleAnimation(backType, adapter, - currentTask, prevTask, currentActivity, prevActivity); - prepareAnimation = mPendingAnimation != null; - mBackAnimationInProgress = prepareAnimation; - if (prepareAnimation) { - mWindowManagerService.mWindowPlacerLocked.requestTraversal(); - if (mShowWallpaper) { - currentTask.getDisplayContent().mWallpaperController - .adjustWallpaperWindows(); + final AnimationHandler.ScheduleAnimationBuilder builder = + mAnimationHandler.prepareAnimation(backType, adapter, + currentTask, prevTask, currentActivity, prevActivity); + mBackAnimationInProgress = builder != null; + if (mBackAnimationInProgress) { + if (removedWindowContainer.hasCommittedReparentToAnimationLeash() + || removedWindowContainer.mTransitionController.inTransition() + || mWindowManagerService.mSyncEngine.hasPendingSyncSets()) { + ProtoLog.w(WM_DEBUG_BACK_PREVIEW, + "Pending back animation due to another animation is running"); + mPendingAnimationBuilder = builder; + // Current transition is still running, we have to defer the hiding to the + // client process to prevent the unexpected relayout when handling the back + // animation. + if (prevActivity != null) { + prevActivity.setDeferHidingClient(true); + } + } else { + scheduleAnimation(builder); } } } @@ -345,6 +351,15 @@ class BackNavigationController { return isWaitBackTransition() || mNavigationMonitor.isMonitoring(); } + private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) { + mPendingAnimation = builder.build(); + mWindowManagerService.mWindowPlacerLocked.requestTraversal(); + if (mShowWallpaper) { + mWindowManagerService.getDefaultDisplayContentLocked().mWallpaperController + .adjustWallpaperWindows(); + } + } + private boolean isWaitBackTransition() { return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition; } @@ -526,6 +541,57 @@ class BackNavigationController { mAnimationHandler.clearBackAnimateTarget(cleanupTransaction); } + /** + * Handle the pending animation when the running transition finished. + * @param targets The final animation targets derived in transition. + */ + boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) { + if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) { + return false; + } + + ProtoLog.d(WM_DEBUG_BACK_PREVIEW, + "Handling the deferred animation after transition finished"); + + // Show the target surface and its parents to prevent it or its parents hidden when + // the transition finished. + // The target could be affected by transition when : + // Open transition -> the open target in back navigation + // Close transition -> the close target in back navigation. + boolean hasTarget = false; + final SurfaceControl.Transaction t = + mPendingAnimationBuilder.mCloseTarget.getPendingTransaction(); + for (int i = 0; i < targets.size(); i++) { + final WindowContainer wc = targets.get(i).mContainer; + if (wc.asActivityRecord() == null && wc.asTask() == null) { + continue; + } else if (!mPendingAnimationBuilder.containTarget(wc)) { + continue; + } + + hasTarget = true; + t.show(wc.getSurfaceControl()); + } + + if (!hasTarget) { + // Skip if no target participated in current finished transition. + Slog.w(TAG, "Finished transition didn't include the targets" + + " open: " + mPendingAnimationBuilder.mOpenTarget + + " close: " + mPendingAnimationBuilder.mCloseTarget); + try { + mPendingAnimationBuilder.mBackAnimationAdapter.getRunner().onAnimationCancelled(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + mPendingAnimationBuilder = null; + return false; + } + + scheduleAnimation(mPendingAnimationBuilder); + mPendingAnimationBuilder = null; + return true; + } + /** * Create and handling animations status for an open/close animation targets. */ @@ -638,6 +704,7 @@ class BackNavigationController { if (open) { return wc == mOpenAdaptor.mTarget || mOpenAdaptor.mTarget.hasChild(wc); } + if (mSwitchType == TASK_SWITCH) { return wc == mCloseAdaptor.mTarget || (wc.asTask() != null && wc.hasChild(mCloseAdaptor.mTarget)); @@ -841,23 +908,22 @@ class BackNavigationController { } } - Runnable scheduleAnimation(int backType, BackAnimationAdapter adapter, + ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter, Task currentTask, Task previousTask, ActivityRecord currentActivity, ActivityRecord previousActivity) { switch (backType) { case BackNavigationInfo.TYPE_RETURN_TO_HOME: return new ScheduleAnimationBuilder(backType, adapter) .setIsLaunchBehind(true) - .setComposeTarget(currentTask, previousTask) - .build(); + .setComposeTarget(currentTask, previousTask); case BackNavigationInfo.TYPE_CROSS_ACTIVITY: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentActivity, previousActivity) - .setOpeningSnapshot(getActivitySnapshot(previousActivity)).build(); + .setOpeningSnapshot(getActivitySnapshot(previousActivity)); case BackNavigationInfo.TYPE_CROSS_TASK: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentTask, previousTask) - .setOpeningSnapshot(getTaskSnapshot(previousTask)).build(); + .setOpeningSnapshot(getTaskSnapshot(previousTask)); } return null; } @@ -891,6 +957,11 @@ class BackNavigationController { return this; } + boolean containTarget(@NonNull WindowContainer wc) { + return wc == mOpenTarget || wc == mCloseTarget + || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget); + } + Runnable build() { if (mOpenTarget == null || mCloseTarget == null) { return null; @@ -967,47 +1038,41 @@ class BackNavigationController { } }; } + } + } - private void setLaunchBehind(ActivityRecord activity) { - if (activity == null) { - return; - } - if (!activity.isVisibleRequested()) { - activity.setVisibility(true); - } - activity.mLaunchTaskBehind = true; - - // Handle fixed rotation launching app. - final DisplayContent dc = activity.mDisplayContent; - dc.rotateInDifferentOrientationIfNeeded(activity); - if (activity.hasFixedRotationTransform()) { - // Set the record so we can recognize it to continue to update display - // orientation if the previous activity becomes the top later. - dc.setFixedRotationLaunchingApp(activity, - activity.getWindowConfiguration().getRotation()); - } + private static void setLaunchBehind(@NonNull ActivityRecord activity) { + if (!activity.isVisibleRequested()) { + activity.setVisibility(true); + } + activity.mLaunchTaskBehind = true; + + // Handle fixed rotation launching app. + final DisplayContent dc = activity.mDisplayContent; + dc.rotateInDifferentOrientationIfNeeded(activity); + if (activity.hasFixedRotationTransform()) { + // Set the record so we can recognize it to continue to update display + // orientation if the previous activity becomes the top later. + dc.setFixedRotationLaunchingApp(activity, + activity.getWindowConfiguration().getRotation()); + } - ProtoLog.d(WM_DEBUG_BACK_PREVIEW, - "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity); - activity.mTaskSupervisor.mStoppingActivities.remove(activity); - activity.getDisplayContent().ensureActivitiesVisible(null /* starting */, - 0 /* configChanges */, false /* preserveWindows */, true); - } - private void restoreLaunchBehind(ActivityRecord activity) { - if (activity == null) { - return; - } + ProtoLog.d(WM_DEBUG_BACK_PREVIEW, + "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity); + activity.mTaskSupervisor.mStoppingActivities.remove(activity); + activity.getDisplayContent().ensureActivitiesVisible(null /* starting */, + 0 /* configChanges */, false /* preserveWindows */, true); + } - activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(); + private static void restoreLaunchBehind(@NonNull ActivityRecord activity) { + activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(); - // Restore the launch-behind state. - activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); - activity.mLaunchTaskBehind = false; - ProtoLog.d(WM_DEBUG_BACK_PREVIEW, - "Setting Activity.mLauncherTaskBehind to false. Activity=%s", - activity); - } - } + // Restore the launch-behind state. + activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); + activity.mLaunchTaskBehind = false; + ProtoLog.d(WM_DEBUG_BACK_PREVIEW, + "Setting Activity.mLauncherTaskBehind to false. Activity=%s", + activity); } void checkAnimationReady(WallpaperController wallpaperController) { @@ -1039,6 +1104,7 @@ class BackNavigationController { mNavigationMonitor.stopMonitor(); mBackAnimationInProgress = false; mShowWallpaper = false; + mPendingAnimationBuilder = null; } private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 86c4e0f7c6c6..87f5703bdbc5 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -38,6 +38,9 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.util.RotationUtils.deltaRotation; +import static android.util.TypedValue.COMPLEX_UNIT_DIP; +import static android.util.TypedValue.COMPLEX_UNIT_MASK; +import static android.util.TypedValue.COMPLEX_UNIT_SHIFT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.view.Display.FLAG_PRIVATE; @@ -170,6 +173,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.ColorSpace; import android.graphics.Insets; @@ -206,6 +210,7 @@ import android.util.Size; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.TypedValue; import android.util.proto.ProtoOutputStream; import android.view.ContentRecordingSession; import android.view.Display; @@ -1684,14 +1689,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private int getMinimalTaskSizeDp() { final Context displayConfigurationContext = mAtmService.mContext.createConfigurationContext(getConfiguration()); - final float minimalSize = - displayConfigurationContext.getResources().getDimension( - R.dimen.default_minimal_size_resizable_task); - if (Double.compare(mDisplayMetrics.density, 0.0) == 0) { - throw new IllegalArgumentException("Display with ID=" + getDisplayId() + "has invalid " - + "DisplayMetrics.density= 0.0"); + final Resources res = displayConfigurationContext.getResources(); + final TypedValue value = new TypedValue(); + res.getValue(R.dimen.default_minimal_size_resizable_task, value, true /* resolveRefs */); + final int valueUnit = ((value.data >> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK); + if (value.type != TypedValue.TYPE_DIMENSION || valueUnit != COMPLEX_UNIT_DIP) { + throw new IllegalArgumentException( + "Resource ID #0x" + Integer.toHexString(R.dimen.default_minimal_size_resizable_task) + + " is not in valid type or unit"); } - return (int) (minimalSize / mDisplayMetrics.density); + return (int) TypedValue.complexToFloat(value.data); } private boolean updateOrientation(boolean forceUpdate) { @@ -4151,13 +4158,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** @see WindowManagerInternal#onToggleImeRequested */ void onShowImeRequested() { - if (mImeLayeringTarget == null || mInputMethodWindow == null) { + if (mInputMethodWindow == null) { return; } // If IME window will be shown on the rotated activity, share the transformed state to // IME window so it can compute rotated frame with rotated configuration. - if (mImeLayeringTarget.mToken.isFixedRotationTransforming()) { - mInputMethodWindow.mToken.linkFixedRotationTransform(mImeLayeringTarget.mToken); + if (mFixedRotationLaunchingApp != null) { + mInputMethodWindow.mToken.linkFixedRotationTransform(mFixedRotationLaunchingApp); // Hide the window until the rotation is done to avoid intermediate artifacts if the // parent surface of IME container is changed. if (mAsyncRotationController != null) { diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index 47bdba34ee24..41eb2c92923f 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -359,12 +359,6 @@ final class DisplayRotationCompatPolicy { CAMERA_OPENED_ROTATION_UPDATE_DELAY_MS); } - private void updateOrientationWithWmLock() { - synchronized (mWmService.mGlobalLock) { - mDisplayContent.updateOrientation(); - } - } - private void delayedUpdateOrientationWithWmLock( @NonNull String cameraId, @NonNull String packageName) { synchronized (this) { @@ -375,25 +369,28 @@ final class DisplayRotationCompatPolicy { } mCameraIdPackageBiMap.put(packageName, cameraId); } - ActivityRecord topActivity = mDisplayContent.topRunningActivity( - /* considerKeyguardState= */ true); - if (topActivity == null || topActivity.getTask() == null) { - return; - } - // Checking whether an activity in fullscreen rather than the task as this camera compat - // treatment doesn't cover activity embedding. - if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { - if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) { - topActivity.recomputeConfiguration(); + synchronized (mWmService.mGlobalLock) { + ActivityRecord topActivity = mDisplayContent.topRunningActivity( + /* considerKeyguardState= */ true); + if (topActivity == null || topActivity.getTask() == null) { + return; + } + // Checking whether an activity in fullscreen rather than the task as this camera + // compat treatment doesn't cover activity embedding. + if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { + if (topActivity.mLetterboxUiController + .isOverrideOrientationOnlyForCameraEnabled()) { + topActivity.recomputeConfiguration(); + } + mDisplayContent.updateOrientation(); + return; + } + // Checking that the whole app is in multi-window mode as we shouldn't show toast + // for the activity embedding case. + if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW + && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) { + showToast(R.string.display_rotation_camera_compat_toast_in_split_screen); } - updateOrientationWithWmLock(); - return; - } - // Checking that the whole app is in multi-window mode as we shouldn't show toast - // for the activity embedding case. - if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW - && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) { - showToast(R.string.display_rotation_camera_compat_toast_in_split_screen); } } @@ -441,18 +438,20 @@ final class DisplayRotationCompatPolicy { ProtoLog.v(WM_DEBUG_ORIENTATION, "Display id=%d is notified that Camera %s is closed, updating rotation.", mDisplayContent.mDisplayId, cameraId); - ActivityRecord topActivity = mDisplayContent.topRunningActivity( - /* considerKeyguardState= */ true); - if (topActivity == null - // Checking whether an activity in fullscreen rather than the task as this camera - // compat treatment doesn't cover activity embedding. - || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { - return; - } - if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) { - topActivity.recomputeConfiguration(); + synchronized (mWmService.mGlobalLock) { + ActivityRecord topActivity = mDisplayContent.topRunningActivity( + /* considerKeyguardState= */ true); + if (topActivity == null + // Checking whether an activity in fullscreen rather than the task as this + // camera compat treatment doesn't cover activity embedding. + || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { + return; + } + if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) { + topActivity.recomputeConfiguration(); + } + mDisplayContent.updateOrientation(); } - updateOrientationWithWmLock(); } private boolean isActivityForCameraIdRefreshing(String cameraId) { diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 210a7d9538c7..c1f2b2be3ea7 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -580,6 +580,13 @@ class InsetsPolicy { // Notification shade has control anyways, no reason to force anything. return focusedWin; } + if (focusedWin != null) { + final InsetsSourceProvider provider = focusedWin.getControllableInsetProvider(); + if (provider != null && provider.getSource().getType() == Type.navigationBars()) { + // Navigation bar has control if it is focused. + return focusedWin; + } + } if (mPolicy.isForceShowNavigationBarEnabled() && focusedWin != null && focusedWin.getActivityType() == ACTIVITY_TYPE_STANDARD) { // When "force show navigation bar" is enabled, it means both force visible is true, and diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index dc674c23abca..44b1cc88c0a4 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -862,10 +862,9 @@ final class LetterboxUiController { return mActivityRecord.mWmService.mContext.getResources(); } - private void handleHorizontalDoubleTap(int x) { - // TODO(b/260857308): Investigate if enabling reachability for translucent activity - if (hasInheritedLetterboxBehavior() || !isHorizontalReachabilityEnabled() - || mActivityRecord.isInTransition()) { + @VisibleForTesting + void handleHorizontalDoubleTap(int x) { + if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) { return; } @@ -903,10 +902,9 @@ final class LetterboxUiController { mActivityRecord.recomputeConfiguration(); } - private void handleVerticalDoubleTap(int y) { - // TODO(b/260857308): Investigate if enabling reachability for translucent activity - if (hasInheritedLetterboxBehavior() || !isVerticalReachabilityEnabled() - || mActivityRecord.isInTransition()) { + @VisibleForTesting + void handleVerticalDoubleTap(int y) { + if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) { return; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index b3b56f273f3d..e147219de4c6 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -33,6 +33,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_PIP; +import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_WAKE; @@ -2329,6 +2330,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void applySleepTokens(boolean applyToRootTasks) { + boolean builtSleepTransition = false; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { // Set the sleeping state of the display. final DisplayContent display = getChildAt(displayNdx); @@ -2338,6 +2340,30 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } display.setIsSleeping(displayShouldSleep); + if (display.mTransitionController.isShellTransitionsEnabled() && !builtSleepTransition + // Only care if there are actual sleep tokens. + && displayShouldSleep && !display.mAllSleepTokens.isEmpty()) { + builtSleepTransition = true; + // We don't actually care about collecting anything here. We really just want + // this as a signal to the transition-player. + final Transition transition = new Transition(TRANSIT_SLEEP, 0 /* flags */, + display.mTransitionController, mWmService.mSyncEngine); + final Runnable sendSleepTransition = () -> { + display.mTransitionController.requestStartTransition(transition, + null /* trigger */, null /* remote */, null /* display */); + // Force playing immediately so that unrelated ops can't be collected. + transition.playNow(); + }; + if (display.mTransitionController.isCollecting()) { + mWmService.mSyncEngine.queueSyncSet( + () -> display.mTransitionController.moveToCollecting(transition), + sendSleepTransition); + } else { + display.mTransitionController.moveToCollecting(transition); + sendSleepTransition.run(); + } + } + if (!applyToRootTasks) { continue; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 0a833f4f2dba..7433c7e58392 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2035,6 +2035,10 @@ class Task extends TaskFragment { Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds(); if (windowingMode == WINDOWING_MODE_FULLSCREEN) { + if (!mCreatedByOrganizer) { + // Use empty bounds to indicate "fill parent". + outOverrideBounds.setEmpty(); + } // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if // the parent or display is smaller than the size, the content may be cropped. return; diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 3cec3aa6a205..76759ba53f5a 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -49,6 +49,7 @@ import android.util.IntArray; import android.util.Slog; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; +import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; @@ -1486,7 +1487,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { */ private boolean isLargeEnoughForMultiWindow() { return getConfiguration().smallestScreenWidthDp - >= mAtmService.mLargeScreenSmallestScreenWidthDp; + >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; } boolean isTopRootTask(Task rootTask) { diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 808e79db0ace..035859e4b87f 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2574,6 +2574,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ TaskFragmentInfo getTaskFragmentInfo() { List<IBinder> childActivities = new ArrayList<>(); + List<IBinder> inRequestedTaskFragmentActivities = new ArrayList<>(); for (int i = 0; i < getChildCount(); i++) { final WindowContainer<?> wc = getChildAt(i); final ActivityRecord ar = wc.asActivityRecord(); @@ -2582,6 +2583,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { && ar.getUid() == mTaskFragmentOrganizerUid && !ar.finishing) { // Only includes Activities that belong to the organizer process for security. childActivities.add(ar.token); + if (ar.mRequestedLaunchingTaskFragmentToken == mFragmentToken) { + inRequestedTaskFragmentActivities.add(ar.token); + } } } final Point positionInParent = new Point(); @@ -2593,6 +2597,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { getNonFinishingActivityCount(), shouldBeVisible(null /* starting */), childActivities, + inRequestedTaskFragmentActivities, positionInParent, mClearedTaskForReuse, mClearedTaskFragmentForPip, diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index a68b3cb2a2ea..bf6983b90fbb 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -218,6 +218,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { final TransitionController.Logger mLogger = new TransitionController.Logger(); + /** Whether this transition was forced to play early (eg for a SLEEP signal). */ + private boolean mForcePlaying = false; + /** * {@code false} if this transition runs purely in WMCore (meaning Shell is completely unaware * of it). Currently, this happens before the display is ready since nothing can be seen yet. @@ -389,6 +392,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mState == STATE_COLLECTING || mState == STATE_STARTED; } + boolean isAborted() { + return mState == STATE_ABORT; + } + boolean isStarted() { return mState == STATE_STARTED; } @@ -813,7 +820,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } boolean hasParticipatedDisplay = false; - boolean reportTaskStackChanged = false; + boolean hasVisibleTransientLaunch = false; // Commit all going-invisible containers for (int i = 0; i < mParticipants.size(); ++i) { final WindowContainer<?> participant = mParticipants.valueAt(i); @@ -856,7 +863,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { && ar.isVisible()) { // Transient launch was committed, so report enteringAnimation ar.mEnteringAnimation = true; - reportTaskStackChanged = true; + hasVisibleTransientLaunch = true; // Since transient launches don't automatically take focus, make sure we // synchronize focus since we committed to the launch. @@ -900,8 +907,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } - if (reportTaskStackChanged) { + if (hasVisibleTransientLaunch) { + // Notify the change about the transient-below task that becomes invisible. mController.mAtm.getTaskChangeNotificationController().notifyTaskStackChanged(); + // Prevent spurious background app switches. + mController.mAtm.stopAppSwitches(); + // The end of transient launch may not reorder task, so make sure to compute the latest + // task rank according to the current visibility. + mController.mAtm.mRootWindowContainer.rankTaskLayers(); } // dispatch legacy callback in a different loop. This is because multiple legacy handlers @@ -983,11 +996,19 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { cleanUpInternal(); mController.updateAnimatingState(mTmpTransaction); mTmpTransaction.apply(); + + // Handle back animation if it's already started. + mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets); } void abort() { // This calls back into itself via controller.abort, so just early return here. if (mState == STATE_ABORT) return; + if (mState == STATE_PENDING) { + // hasn't started collecting, so can jump directly to aborted state. + mState = STATE_ABORT; + return; + } if (mState != STATE_COLLECTING && mState != STATE_STARTED) { throw new IllegalStateException("Too late to abort. state=" + mState); } @@ -998,6 +1019,27 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mController.dispatchLegacyAppTransitionCancelled(); } + /** Immediately moves this to playing even if it isn't started yet. */ + void playNow() { + if (!(mState == STATE_COLLECTING || mState == STATE_STARTED)) { + return; + } + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Force Playing Transition: %d", + mSyncId); + mForcePlaying = true; + setAllReady(); + if (mState == STATE_COLLECTING) { + start(); + } + // Don't wait for actual surface-placement. We don't want anything else collected in this + // transition. + mSyncEngine.onSurfacePlacement(); + } + + boolean isForcePlaying() { + return mForcePlaying; + } + void setRemoteTransition(RemoteTransition remoteTransition) { mRemoteTransition = remoteTransition; } diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 79eb63462d0b..6c951bfc5f9a 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -209,6 +209,12 @@ class TransitionController { if (mCollectingTransition != null) { throw new IllegalStateException("Simultaneous transition collection not supported."); } + if (mTransitionPlayer == null) { + // If sysui has been killed (by a test) or crashed, we can temporarily have no player + // In this case, abort the transition. + transition.abort(); + return; + } mCollectingTransition = transition; // Distinguish change type because the response time is usually expected to be not too long. final long timeoutMs = @@ -511,6 +517,14 @@ class TransitionController { transition.getToken(), null)); return transition; } + if (mTransitionPlayer == null || transition.isAborted()) { + // Apparently, some tests will kill(and restart) systemui, so there is a chance that + // the player might be transiently null. + if (transition.isCollecting()) { + transition.abort(); + } + return transition; + } try { ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Requesting StartTransition: %s", transition); diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 16541c10d9db..2b848d57e2f9 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -37,6 +37,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; import android.annotation.Nullable; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; @@ -55,6 +56,7 @@ import android.view.WindowManager; import android.view.animation.Animation; import android.window.ScreenCapture; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; @@ -72,7 +74,7 @@ import java.util.function.Consumer; class WallpaperController { private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM; private WindowManagerService mService; - private final DisplayContent mDisplayContent; + private DisplayContent mDisplayContent; private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>(); @@ -120,9 +122,19 @@ class WallpaperController { private boolean mShouldOffsetWallpaperCenter; + final boolean mEnableSeparateLockScreenEngine; + private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> { if ((w.mAttrs.type == TYPE_WALLPAPER)) { if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) { + WallpaperWindowToken token = w.mToken.asWallpaperToken(); + if (token == null) { + Slog.w(TAG, "Window " + w + " has wallpaper type but not wallpaper token"); + return false; + } + if (!token.canShowWhenLocked() && mDisplayContent.isKeyguardLocked()) { + return false; + } mFindResults.setTopWallpaper(w); mFindResults.resetTopWallpaper = false; } @@ -249,11 +261,14 @@ class WallpaperController { WallpaperController(WindowManagerService service, DisplayContent displayContent) { mService = service; mDisplayContent = displayContent; - mMaxWallpaperScale = service.mContext.getResources() - .getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale); - mShouldOffsetWallpaperCenter = service.mContext.getResources() - .getBoolean( + Resources resources = service.mContext.getResources(); + mMaxWallpaperScale = + resources.getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale); + mShouldOffsetWallpaperCenter = + resources.getBoolean( com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay); + mEnableSeparateLockScreenEngine = + resources.getBoolean(R.bool.config_independentLockscreenLiveWallpaper); } void resetLargestDisplay(Display display) { @@ -753,10 +768,10 @@ class WallpaperController { result.setWallpaperTarget(wallpaperTarget); } - private void updateWallpaperTokens(boolean visible) { + private void updateWallpaperTokens(boolean visibility, boolean locked) { for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); - token.updateWallpaperWindows(visible); + token.updateWallpaperWindows(visibility && (!locked || token.canShowWhenLocked())); } } @@ -794,7 +809,13 @@ class WallpaperController { } } - updateWallpaperTokens(visible); + // Keep both wallpapers visible unless the keyguard is locked (then hide private wp) + updateWallpaperTokens(visible, mDisplayContent.isKeyguardLocked()); + + if (DEBUG_WALLPAPER) { + Slog.v(TAG, "adjustWallpaperWindows: wallpaper visibility " + visible + + ", lock visibility " + mDisplayContent.isKeyguardLocked()); + } if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) { mLastFrozen = mFindResults.isWallpaperTargetForLetterbox; @@ -896,7 +917,6 @@ class WallpaperController { mWallpaperTokens.remove(token); } - @VisibleForTesting boolean canScreenshotWallpaper() { return canScreenshotWallpaper(getTopVisibleWallpaper()); diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 8708f73980c6..17ab551b5c1e 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -76,14 +76,18 @@ class WallpaperWindowToken extends WindowToken { return; } mShowWhenLocked = showWhenLocked; - - // Move the window token to the front (private) or back (showWhenLocked). This is possible - // because the DisplayArea underneath TaskDisplayArea only contains TYPE_WALLPAPER windows. - final int position = showWhenLocked ? POSITION_BOTTOM : POSITION_TOP; - - // Note: Moving all the way to the front or back breaks ordering based on addition times. - // We should never have more than one non-animating token of each type. - getParent().positionChildAt(position, this /* child */, false /*includingParents */); + if (mDisplayContent.mWallpaperController.mEnableSeparateLockScreenEngine) { + // Move the window token to the front (private) or back (showWhenLocked). This is + // possible + // because the DisplayArea underneath TaskDisplayArea only contains TYPE_WALLPAPER + // windows. + final int position = showWhenLocked ? POSITION_BOTTOM : POSITION_TOP; + + // Note: Moving all the way to the front or back breaks ordering based on addition + // times. + // We should never have more than one non-animating token of each type. + getParent().positionChildAt(position, this /* child */, false /*includingParents */); + } } boolean canShowWhenLocked() { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 8e22821820a1..495d7ce4e90b 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -74,7 +74,9 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Parcel; import android.os.RemoteException; import android.util.AndroidRuntimeException; @@ -315,7 +317,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } transition = mTransitionController.createTransition(type); } - if (!transition.isCollecting()) { + if (!transition.isCollecting() && !transition.isForcePlaying()) { Slog.e(TAG, "Trying to start a transition that isn't collecting. This probably" + " means Shell took too long to respond to a request. WM State may be" + " incorrect now, please file a bug"); @@ -998,11 +1000,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub activityOptions.setCallerDisplayId(DEFAULT_DISPLAY); } final Bundle options = activityOptions != null ? activityOptions.toBundle() : null; - waitAsyncStart(() -> mService.mAmInternal.sendIntentSender( + int res = waitAsyncStart(() -> mService.mAmInternal.sendIntentSender( hop.getPendingIntent().getTarget(), hop.getPendingIntent().getWhitelistToken(), 0 /* code */, hop.getActivityIntent(), resolvedType, null /* finishReceiver */, null /* requiredPermission */, options)); + if (ActivityManager.isStartResultSuccessful(res)) { + effects |= TRANSACT_EFFECTS_LIFECYCLE; + } break; } case HIERARCHY_OP_TYPE_START_SHORTCUT: { @@ -1353,9 +1358,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub * Post and wait for the result of the activity start to prevent potential deadlock against * {@link WindowManagerGlobalLock}. */ - private void waitAsyncStart(IntSupplier startActivity) { + private int waitAsyncStart(IntSupplier startActivity) { final Integer[] starterResult = {null}; - mService.mH.post(() -> { + final Handler handler = (Looper.myLooper() == mService.mH.getLooper()) + // uncommon case where a queued transaction is trying to start an activity. We can't + // post to our own thread and wait (otherwise we deadlock), so use anim thread + // instead (which is 1 higher priority). + ? mService.mWindowManager.mAnimationHandler + // Otherwise just put it on main handler + : mService.mH; + handler.post(() -> { try { starterResult[0] = startActivity.getAsInt(); } catch (Throwable t) { @@ -1372,6 +1384,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } catch (InterruptedException ignored) { } } + return starterResult[0]; } private int sanitizeAndApplyHierarchyOp(WindowContainer container, diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index aa10291a0364..694f1be67d1a 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1826,6 +1826,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio pw.print("F|"); } } + if ((stateFlags & ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK) != 0) { + pw.print("VT|"); + } final int taskLayer = stateFlags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER; if (taskLayer != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) { pw.print("taskLayer=" + taskLayer); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 87e87b95fdfd..cf0fc0995a9b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2018,16 +2018,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** * Like isOnScreen(), but we don't return true if the window is part - * of a transition that has not yet been started. + * of a transition but has not yet started animating. */ boolean isReadyForDisplay() { - if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()) { + if (!mHasSurface || mDestroying || !isVisibleByPolicy()) { + return false; + } + if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet() + && !isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)) { return false; } final boolean parentAndClientVisible = !isParentWindowHidden() && mViewVisibility == View.VISIBLE && mToken.isVisible(); - return mHasSurface && isVisibleByPolicy() && !mDestroying - && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS)); + return parentAndClientVisible || isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_ALL); } boolean isFullyTransparent() { @@ -2342,9 +2345,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override public void onConfigurationChanged(Configuration newParentConfig) { - mTempConfiguration.setTo(getConfiguration()); + // Get from super to avoid using the updated global config from the override method. + final Configuration selfConfiguration = super.getConfiguration(); + mTempConfiguration.setTo(selfConfiguration); super.onConfigurationChanged(newParentConfig); - final int diff = getConfiguration().diff(mTempConfiguration); + final int diff = selfConfiguration.diff(mTempConfiguration); if (diff != 0) { mLastConfigReportedToClient = false; } diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 9260d2b4194a..981844cf9338 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -26,6 +26,10 @@ <xs:element name="displayConfiguration"> <xs:complexType> <xs:sequence> + <xs:element type ="xs:string" name="name"> + <xs:annotation name="nullable"/> + <xs:annotation name="final"/> + </xs:element> <xs:element type="densityMapping" name="densityMapping" minOccurs="0" maxOccurs="1"> <xs:annotation name="nullable"/> <xs:annotation name="final"/> @@ -211,6 +215,32 @@ <xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap" maxOccurs="unbounded"> <xs:annotation name="final"/> </xs:element> + <xs:element type="refreshRateThrottlingMap" name="refreshRateThrottlingMap" maxOccurs="unbounded"> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="refreshRateThrottlingMap"> + <xs:attribute name="id" type="xs:string" /> + <xs:sequence> + <xs:element name="refreshRateThrottlingPoint" type="refreshRateThrottlingPoint" maxOccurs="unbounded"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="refreshRateThrottlingPoint"> + <xs:sequence> + <xs:element type="thermalStatus" name="thermalStatus"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element type="refreshRateRange" name="refreshRateRange"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> </xs:sequence> </xs:complexType> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index e81c27d94c88..8cb483770c85 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -89,6 +89,7 @@ package com.android.server.display.config { method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle(); method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode(); method public final com.android.server.display.config.SensorDetails getLightSensor(); + method @Nullable public final String getName(); method public final com.android.server.display.config.SensorDetails getProxSensor(); method public com.android.server.display.config.DisplayQuirks getQuirks(); method public com.android.server.display.config.RefreshRateConfigs getRefreshRate(); @@ -114,6 +115,7 @@ package com.android.server.display.config { method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds); method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode); method public final void setLightSensor(com.android.server.display.config.SensorDetails); + method public final void setName(@Nullable String); method public final void setProxSensor(com.android.server.display.config.SensorDetails); method public void setQuirks(com.android.server.display.config.DisplayQuirks); method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs); @@ -214,6 +216,21 @@ package com.android.server.display.config { method public final void setMinimum(java.math.BigInteger); } + public class RefreshRateThrottlingMap { + ctor public RefreshRateThrottlingMap(); + method public String getId(); + method @NonNull public final java.util.List<com.android.server.display.config.RefreshRateThrottlingPoint> getRefreshRateThrottlingPoint(); + method public void setId(String); + } + + public class RefreshRateThrottlingPoint { + ctor public RefreshRateThrottlingPoint(); + method @NonNull public final com.android.server.display.config.RefreshRateRange getRefreshRateRange(); + method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus(); + method public final void setRefreshRateRange(@NonNull com.android.server.display.config.RefreshRateRange); + method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus); + } + public class RefreshRateZone { ctor public RefreshRateZone(); method public String getId(); @@ -264,6 +281,7 @@ package com.android.server.display.config { public class ThermalThrottling { ctor public ThermalThrottling(); method public final java.util.List<com.android.server.display.config.BrightnessThrottlingMap> getBrightnessThrottlingMap(); + method public final java.util.List<com.android.server.display.config.RefreshRateThrottlingMap> getRefreshRateThrottlingMap(); } public class ThresholdPoint { diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd index d4556d710429..ce022e9cb78d 100644 --- a/services/core/xsd/display-layout-config/display-layout-config.xsd +++ b/services/core/xsd/display-layout-config/display-layout-config.xsd @@ -52,6 +52,7 @@ <xs:element name="address" type="xs:nonNegativeInteger"/> <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" /> <xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" /> </xs:sequence> <xs:attribute name="enabled" type="xs:boolean" use="optional" /> <xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" /> diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt index 52133ab76086..42a800db1474 100644 --- a/services/core/xsd/display-layout-config/schema/current.txt +++ b/services/core/xsd/display-layout-config/schema/current.txt @@ -7,6 +7,7 @@ package com.android.server.display.config.layout { method public String getBrightnessThrottlingMapId(); method public String getDisplayGroup(); method public String getPosition(); + method public String getRefreshRateThermalThrottlingMapId(); method public String getRefreshRateZoneId(); method public boolean isDefaultDisplay(); method public boolean isEnabled(); @@ -16,6 +17,7 @@ package com.android.server.display.config.layout { method public void setDisplayGroup(String); method public void setEnabled(boolean); method public void setPosition(String); + method public void setRefreshRateThermalThrottlingMapId(String); method public void setRefreshRateZoneId(String); } diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index f8b1e6fc927c..c8ec7c20650b 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -29,6 +29,9 @@ import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialProviderInfo; import android.util.Log; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; + import java.util.ArrayList; /** @@ -116,21 +119,23 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta private void respondToClientWithResponseAndFinish() { Log.i(TAG, "respondToClientWithResponseAndFinish"); if (isSessionCancelled()) { - // TODO: Differentiate btw cancelled and false mChosenProviderMetric.setChosenProviderStatus( MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_SUCCESS); - logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.CLEAR_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_CLIENT_CANCELED); finishSession(/*propagateCancellation=*/true); return; } try { mClientCallback.onSuccess(); - logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.CLEAR_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_SUCCESS); } catch (RemoteException e) { mChosenProviderMetric.setChosenProviderStatus( MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_FAILURE); Log.i(TAG, "Issue while propagating the response to the client"); - logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ false); + logApiCall(ApiName.CLEAR_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_FAILURE); } finishSession(/*propagateCancellation=*/false); } @@ -138,8 +143,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) { Log.i(TAG, "respondToClientWithErrorAndFinish"); if (isSessionCancelled()) { - // TODO: Differentiate btw cancelled and false - logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.CLEAR_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_CLIENT_CANCELED); finishSession(/*propagateCancellation=*/true); return; } @@ -148,7 +153,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta } catch (RemoteException e) { e.printStackTrace(); } - logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ false); + logApiCall(ApiName.CLEAR_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_FAILURE); finishSession(/*propagateCancellation=*/false); } diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 4dd0c84d64f6..0c1133ce8793 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -36,6 +36,9 @@ import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialProviderInfo; import android.util.Log; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; + import java.util.ArrayList; /** @@ -140,17 +143,19 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR return; } if (isSessionCancelled()) { - // TODO: Differentiate btw cancelled and false - logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.CREATE_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_CLIENT_CANCELED); finishSession(/*propagateCancellation=*/true); return; } try { mClientCallback.onResponse(response); - logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.CREATE_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_SUCCESS); } catch (RemoteException e) { Log.i(TAG, "Issue while responding to client: " + e.getMessage()); - logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ false); + logApiCall(ApiName.CREATE_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_FAILURE); } finishSession(/*propagateCancellation=*/false); } @@ -162,8 +167,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR return; } if (isSessionCancelled()) { - // TODO: Differentiate btw cancelled and false - logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.CREATE_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_CLIENT_CANCELED); finishSession(/*propagateCancellation=*/true); return; } @@ -172,10 +177,20 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR } catch (RemoteException e) { Log.i(TAG, "Issue while responding to client: " + e.getMessage()); } - logApiCalled(RequestType.CREATE_CREDENTIALS, /* isSuccessful */ false); + logFailureOrUserCancel(errorType); finishSession(/*propagateCancellation=*/false); } + private void logFailureOrUserCancel(String errorType) { + if (CreateCredentialException.TYPE_USER_CANCELED.equals(errorType)) { + logApiCall(ApiName.CREATE_CREDENTIAL, + /* apiStatus */ ApiStatus.METRICS_API_STATUS_USER_CANCELED); + } else { + logApiCall(ApiName.CREATE_CREDENTIAL, + /* apiStatus */ ApiStatus.METRICS_API_STATUS_FAILURE); + } + } + @Override public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName) { diff --git a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java index 9c50a5ac2b16..d768d234cd20 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java +++ b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java @@ -23,6 +23,8 @@ import android.service.credentials.CredentialEntry; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + import java.util.HashMap; import java.util.HashSet; @@ -90,6 +92,18 @@ public final class CredentialDescriptionRegistry { } } + /** Clears an existing session for a given user identifier. */ + @GuardedBy("sLock") + @VisibleForTesting + public static void clearAllSessions() { + sLock.lock(); + try { + sCredentialDescriptionSessionPerUser.clear(); + } finally { + sLock.unlock(); + } + } + private Map<String, Set<CredentialDescription>> mCredentialDescriptions; private int mTotalDescriptionCount; @@ -138,6 +152,9 @@ public final class CredentialDescriptionRegistry { public Set<FilterResult> getFilteredResultForProvider(String packageName, String flatRequestStrings) { Set<FilterResult> result = new HashSet<>(); + if (!mCredentialDescriptions.containsKey(packageName)) { + return result; + } Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription: currentSet) { if (flatRequestStrings.equals(containedDescription.getFlattenedRequestString())) { diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 7a4e7dfd56a3..41ae9118d965 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -64,6 +64,8 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.SecureSettingsServiceNameResolver; @@ -84,7 +86,7 @@ import java.util.stream.Collectors; */ public final class CredentialManagerService extends AbstractMasterSystemService< - CredentialManagerService, CredentialManagerServiceImpl> { + CredentialManagerService, CredentialManagerServiceImpl> { private static final String TAG = "CredManSysService"; private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API = @@ -267,7 +269,8 @@ public final class CredentialManagerService final long origId = Binder.clearCallingIdentity(); try { return DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, false); + DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, + false); } finally { Binder.restoreCallingIdentity(origId); } @@ -317,8 +320,8 @@ public final class CredentialManagerService Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>> result = new HashSet<>(); - for (CredentialDescriptionRegistry.FilterResult filterResult: filterResults) { - for (CredentialOption credentialOption: options) { + for (CredentialDescriptionRegistry.FilterResult filterResult : filterResults) { + for (CredentialOption credentialOption : options) { if (filterResult.mFlattenedRequest.equals(credentialOption .getCredentialRetrievalData() .getString(CredentialOption.FLATTENED_REQUEST))) { @@ -364,13 +367,13 @@ public final class CredentialManagerService CallingAppInfo callingAppInfo; try { packageInfo = - getContext() - .getPackageManager() - .getPackageInfoAsUser( - realPackageName, - PackageManager.PackageInfoFlags.of( - PackageManager.GET_SIGNING_CERTIFICATES), - userId); + getContext() + .getPackageManager() + .getPackageInfoAsUser( + realPackageName, + PackageManager.PackageInfoFlags.of( + PackageManager.GET_SIGNING_CERTIFICATES), + userId); callingAppInfo = new CallingAppInfo(realPackageName, packageInfo.signingInfo, origin); } catch (PackageManager.NameNotFoundException e) { Log.i(TAG, "Issue while retrieving signatureInfo : " + e.getMessage()); @@ -421,41 +424,41 @@ public final class CredentialManagerService if (isCredentialDescriptionApiEnabled()) { List<CredentialOption> optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - !TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) - .toList(); + .filter( + getCredentialOption -> + !TextUtils.isEmpty( + getCredentialOption + .getCredentialRetrievalData() + .getString( + CredentialOption + .FLATTENED_REQUEST, + null))) + .toList(); List<CredentialOption> optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) - .toList(); + .filter( + getCredentialOption -> + TextUtils.isEmpty( + getCredentialOption + .getCredentialRetrievalData() + .getString( + CredentialOption + .FLATTENED_REQUEST, + null))) + .toList(); List<ProviderSession> sessionsWithoutRemoteService = initiateProviderSessionsWithActiveContainers( - session, - getFilteredResultFromRegistry(optionsThatRequireActiveCredentials)); + session, + getFilteredResultFromRegistry(optionsThatRequireActiveCredentials)); List<ProviderSession> sessionsWithRemoteService = initiateProviderSessions( - session, - optionsThatDoNotRequireActiveCredentials.stream() - .map(CredentialOption::getType) - .collect(Collectors.toList())); + session, + optionsThatDoNotRequireActiveCredentials.stream() + .map(CredentialOption::getType) + .collect(Collectors.toList())); Set<ProviderSession> all = new LinkedHashSet<>(); all.addAll(sessionsWithRemoteService); @@ -465,11 +468,11 @@ public final class CredentialManagerService } else { // Initiate all provider sessions providerSessions = - initiateProviderSessions( - session, - request.getCredentialOptions().stream() - .map(CredentialOption::getType) - .collect(Collectors.toList())); + initiateProviderSessions( + session, + request.getCredentialOptions().stream() + .map(CredentialOption::getType) + .collect(Collectors.toList())); } if (providerSessions.isEmpty()) { @@ -481,8 +484,8 @@ public final class CredentialManagerService Log.i( TAG, "Issue invoking onError on IGetCredentialCallback " - + "callback: " - + e.getMessage()); + + "callback: " + + e.getMessage()); } } providerSessions.forEach(ProviderSession::invokeSession); @@ -538,8 +541,8 @@ public final class CredentialManagerService Log.i( TAG, "Issue invoking onError on ICreateCredentialCallback " - + "callback: " - + e.getMessage()); + + "callback: " + + e.getMessage()); } } @@ -654,13 +657,17 @@ public final class CredentialManagerService if (serviceComponentName.equals(componentName)) { if (!s.getServicePackageName().equals(callingPackage)) { // The component name and the package name do not match. + MetricUtilities.logApiCalled( + ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, + ApiStatus.METRICS_API_STATUS_FAILURE, callingUid); Log.w( TAG, "isEnabledCredentialProviderService: Component name does not" + " match package name."); return false; } - + MetricUtilities.logApiCalled(ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE, + ApiStatus.METRICS_API_STATUS_SUCCESS, callingUid); return true; } } @@ -745,7 +752,7 @@ public final class CredentialManagerService enforceCallingPackage(callingPackage, Binder.getCallingUid()); List<CredentialProviderInfo> services = - getServicesForCredentialDescription(UserHandle.getCallingUserId()); + getServicesForCredentialDescription(UserHandle.getCallingUserId()); List<String> providers = services.stream() @@ -801,7 +808,7 @@ public final class CredentialManagerService enforceCallingPackage(callingPackage, Binder.getCallingUid()); List<CredentialProviderInfo> services = - getServicesForCredentialDescription(UserHandle.getCallingUserId()); + getServicesForCredentialDescription(UserHandle.getCallingUserId()); List<String> providers = services.stream() diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index 32b14d773b95..13f4b542a83e 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -34,6 +34,9 @@ import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialProviderInfo; import android.util.Log; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; + import java.util.ArrayList; /** @@ -116,17 +119,19 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest return; } if (isSessionCancelled()) { - // TODO: Differentiate btw cancelled and false - logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ false); + logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_CLIENT_CANCELED); finishSession(/*propagateCancellation=*/true); return; } try { mClientCallback.onResponse(response); - logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ true); + logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_SUCCESS); } catch (RemoteException e) { Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage()); - logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ false); + logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_FAILURE); } finishSession(/*propagateCancellation=*/false); } @@ -137,7 +142,8 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest return; } if (isSessionCancelled()) { - logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ false); + logApiCall(ApiName.GET_CREDENTIAL, /* apiStatus */ + ApiStatus.METRICS_API_STATUS_CLIENT_CANCELED); finishSession(/*propagateCancellation=*/true); return; } @@ -147,10 +153,20 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest } catch (RemoteException e) { Log.i(TAG, "Issue while responding to client with error : " + e.getMessage()); } - logApiCalled(RequestType.GET_CREDENTIALS, /* isSuccessful */ false); + logFailureOrUserCancel(errorType); finishSession(/*propagateCancellation=*/false); } + private void logFailureOrUserCancel(String errorType) { + if (GetCredentialException.TYPE_USER_CANCELED.equals(errorType)) { + logApiCall(ApiName.GET_CREDENTIAL, + /* apiStatus */ ApiStatus.METRICS_API_STATUS_USER_CANCELED); + } else { + logApiCall(ApiName.GET_CREDENTIAL, + /* apiStatus */ ApiStatus.METRICS_API_STATUS_FAILURE); + } + } + @Override public void onUiCancellation(boolean isUserCancellation) { if (isUserCancellation) { diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index 27d9836d9b66..e7b0a2d9f731 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -16,14 +16,6 @@ package com.android.server.credentials; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_CLIENT_CANCELED; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS; -import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_USER_CANCELED; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_FAILURE; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_SUCCESS; import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_QUERY_FAILURE; @@ -35,6 +27,14 @@ import android.content.Context; import android.content.pm.PackageManager; import android.util.Log; +import com.android.internal.util.FrameworkStatsLog; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; +import com.android.server.credentials.metrics.CandidateProviderMetric; +import com.android.server.credentials.metrics.ChosenProviderMetric; + +import java.util.Map; + /** * For all future metric additions, this will contain their names for local usage after importing * from {@link com.android.internal.util.FrameworkStatsLog}. @@ -43,24 +43,10 @@ public class MetricUtilities { private static final String TAG = "MetricUtilities"; - // Metrics constants - protected static final int METRICS_API_NAME_UNKNOWN = - CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN; - protected static final int METRICS_API_NAME_GET_CREDENTIAL = - CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL; - protected static final int METRICS_API_NAME_CREATE_CREDENTIAL = - CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL; - protected static final int METRICS_API_NAME_CLEAR_CREDENTIAL = - CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL; - // TODO add isEnabled - protected static final int METRICS_API_STATUS_SUCCESS = - CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS; - protected static final int METRICS_API_STATUS_FAILURE = - CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE; - protected static final int METRICS_API_STATUS_CLIENT_CANCEL = - CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_CLIENT_CANCELED; - protected static final int METRICS_API_STATUS_USER_CANCEL = - CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_USER_CANCELED; + public static final int DEFAULT_INT_32 = -1; + public static final int[] DEFAULT_REPEATED_INT_32 = new int[0]; + + // Metrics constants TODO(b/269290341) migrate to enums eventually to improve protected static final int METRICS_PROVIDER_STATUS_FINAL_FAILURE = CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_FAILURE; protected static final int METRICS_PROVIDER_STATUS_QUERY_FAILURE = @@ -77,6 +63,7 @@ public class MetricUtilities { * This retrieves the uid of any package name, given a context and a component name for the * package. By default, if the desired package uid cannot be found, it will fall back to a * bogus uid. + * * @return the uid of a given package */ protected static int getPackageUid(Context context, ComponentName componentName) { @@ -92,4 +79,92 @@ public class MetricUtilities { return sessUid; } + /** + * Given any two timestamps in nanoseconds, this gets the difference and converts to + * milliseconds. Assumes the difference is not larger than the maximum int size. + * + * @param t2 the final timestamp + * @param t1 the initial timestamp + * @return the timestamp difference converted to microseconds + */ + protected static int getMetricTimestampDifferenceMicroseconds(long t2, long t1) { + if (t2 - t1 > Integer.MAX_VALUE) { + throw new ArithmeticException("Input timestamps are too far apart and unsupported"); + } + return (int) ((t2 - t1) / 1000); + } + + /** + * The most common logging helper, handles the overall status of the API request with the + * provider status and latencies. Other versions of this method may be more useful depending + * on the situation, as this is geared towards the logging of {@link ProviderSession} types. + * + * @param apiName the api type to log + * @param apiStatus the api status to log + * @param providers a map with known providers + * @param callingUid the calling UID of the client app + * @param chosenProviderMetric the metric data type of the final chosen provider + */ + protected static void logApiCalled(ApiName apiName, ApiStatus apiStatus, + Map<String, ProviderSession> providers, int callingUid, + ChosenProviderMetric chosenProviderMetric) { + var providerSessions = providers.values(); + int providerSize = providerSessions.size(); + int[] candidateUidList = new int[providerSize]; + int[] candidateQueryRoundTripTimeList = new int[providerSize]; + int[] candidateStatusList = new int[providerSize]; + int index = 0; + for (var session : providerSessions) { + CandidateProviderMetric metric = session.mCandidateProviderMetric; + candidateUidList[index] = metric.getCandidateUid(); + candidateQueryRoundTripTimeList[index] = metric.getQueryLatencyMicroseconds(); + candidateStatusList[index] = metric.getProviderQueryStatus(); + index++; + } + FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED, + /* api_name */apiName.getMetricCode(), + /* caller_uid */ callingUid, + /* api_status */ apiStatus.getMetricCode(), + /* repeated_candidate_provider_uid */ candidateUidList, + /* repeated_candidate_provider_round_trip_time_query_microseconds */ + candidateQueryRoundTripTimeList, + /* repeated_candidate_provider_status */ candidateStatusList, + /* chosen_provider_uid */ chosenProviderMetric.getChosenUid(), + /* chosen_provider_round_trip_time_overall_microseconds */ + chosenProviderMetric.getEntireProviderLatencyMicroseconds(), + /* chosen_provider_final_phase_microseconds (backwards compat only) */ + getMetricTimestampDifferenceMicroseconds(chosenProviderMetric + .getFinalFinishTimeNanoseconds(), + chosenProviderMetric.getUiCallEndTimeNanoseconds()), + /* chosen_provider_status */ chosenProviderMetric.getChosenProviderStatus()); + } + + /** + * This is useful just to record an API calls' final event, and for no other purpose. It will + * contain default values for all other optional parameters. + * + * TODO(b/271135048) - given space requirements, this may be a good candidate for another atom + * + * @param apiName the api name to log + * @param apiStatus the status to log + * @param callingUid the calling uid + */ + protected static void logApiCalled(ApiName apiName, ApiStatus apiStatus, + int callingUid) { + FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED, + /* api_name */apiName.getMetricCode(), + /* caller_uid */ callingUid, + /* api_status */ apiStatus.getMetricCode(), + /* repeated_candidate_provider_uid */ DEFAULT_REPEATED_INT_32, + /* repeated_candidate_provider_round_trip_time_query_microseconds */ + DEFAULT_REPEATED_INT_32, + /* repeated_candidate_provider_status */ DEFAULT_REPEATED_INT_32, + /* chosen_provider_uid */ DEFAULT_INT_32, + /* chosen_provider_round_trip_time_overall_microseconds */ + DEFAULT_INT_32, + /* chosen_provider_final_phase_microseconds */ + DEFAULT_INT_32, + /* chosen_provider_status */ DEFAULT_INT_32); + } + } diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java index ce9fca753a06..941d9ad26dca 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java @@ -119,8 +119,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredential @Override protected void invokeSession() { if (mRemoteCredentialService != null) { + mCandidateProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); - mCandidateProviderMetric.setStartTimeNanoseconds(System.nanoTime()); } } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java index 3245c914b2b8..17caba5831e8 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java @@ -35,6 +35,7 @@ import android.service.credentials.CreateCredentialRequest; import android.service.credentials.CreateEntry; import android.service.credentials.CredentialProviderInfo; import android.service.credentials.CredentialProviderService; +import android.service.credentials.RemoteEntry; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -136,7 +137,8 @@ public final class ProviderCreateSession extends ProviderSession< remoteCredentialService); mCompleteRequest = completeCreateRequest; setStatus(Status.PENDING); - mProviderResponseDataHandler = new ProviderResponseDataHandler(hybridService); + mProviderResponseDataHandler = new ProviderResponseDataHandler( + ComponentName.unflattenFromString(hybridService)); } @Override @@ -224,8 +226,8 @@ public final class ProviderCreateSession extends ProviderSession< @Override protected void invokeSession() { if (mRemoteCredentialService != null) { + mCandidateProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); mRemoteCredentialService.onCreateCredential(mProviderRequest, this); - mCandidateProviderMetric.setStartTimeNanoseconds(System.nanoTime()); } } @@ -296,21 +298,23 @@ public final class ProviderCreateSession extends ProviderSession< } private class ProviderResponseDataHandler { - private final ComponentName mExpectedRemoteEntryProviderService; + @Nullable private final ComponentName mExpectedRemoteEntryProviderService; @NonNull private final Map<String, Pair<CreateEntry, Entry>> mUiCreateEntries = new HashMap<>(); - @Nullable private Pair<String, Pair<CreateEntry, Entry>> mUiRemoteEntry = null; + @Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null; - ProviderResponseDataHandler(String hybridService) { - mExpectedRemoteEntryProviderService = ComponentName.unflattenFromString(hybridService); + ProviderResponseDataHandler(@Nullable ComponentName expectedRemoteEntryProviderService) { + mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService; } public void addResponseContent(List<CreateEntry> createEntries, - CreateEntry remoteEntry) { + RemoteEntry remoteEntry) { createEntries.forEach(this::addCreateEntry); - setRemoteEntry(remoteEntry); + if (remoteEntry != null) { + setRemoteEntry(remoteEntry); + } } public void addCreateEntry(CreateEntry createEntry) { String id = generateUniqueId(); @@ -319,14 +323,14 @@ public final class ProviderCreateSession extends ProviderSession< mUiCreateEntries.put(id, new Pair<>(createEntry, entry)); } - public void setRemoteEntry(@Nullable CreateEntry remoteEntry) { - if (remoteEntry == null) { - mUiRemoteEntry = null; + public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) { + if (!enforceRemoteEntryRestrictions(mExpectedRemoteEntryProviderService)) { + Log.i(TAG, "Remote entry being dropped as it does not meet the restriction" + + "checks."); return; } - if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) { - Log.i(TAG, "Remote entry being dropped as it is not from the service " - + "configured by the OEM."); + if (remoteEntry == null) { + mUiRemoteEntry = null; return; } String id = generateUniqueId(); @@ -363,7 +367,7 @@ public final class ProviderCreateSession extends ProviderSession< return mUiCreateEntries.isEmpty() && mUiRemoteEntry == null; } @Nullable - public CreateEntry getRemoteEntry(String entryKey) { + public RemoteEntry getRemoteEntry(String entryKey) { return mUiRemoteEntry == null || mUiRemoteEntry .first == null || !mUiRemoteEntry.first.equals(entryKey) || mUiRemoteEntry.second == null diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 6498b6afe208..b8b11ebd13f0 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -38,6 +38,7 @@ import android.service.credentials.CredentialEntry; import android.service.credentials.CredentialProviderInfo; import android.service.credentials.CredentialProviderService; import android.service.credentials.GetCredentialRequest; +import android.service.credentials.RemoteEntry; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -180,7 +181,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential /** Called when the provider response has been updated by an external source. */ @Override // Callback from the remote provider public void onProviderResponseSuccess(@Nullable BeginGetCredentialResponse response) { - Log.i(TAG, "in onProviderResponseSuccess"); onSetInitialRemoteResponse(response); } @@ -268,8 +268,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential @Override protected void invokeSession() { if (mRemoteCredentialService != null) { + mCandidateProviderMetric.setStartQueryTimeNanoseconds(System.nanoTime()); mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); - mCandidateProviderMetric.setStartTimeNanoseconds(System.nanoTime()); } } @@ -299,7 +299,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential } return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, new GetCredentialRequest( - mCallingAppInfo, mBeginGetOptionToCredentialOptionMap.get(id))); + mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id)))); } private Intent setUpFillInIntentWithQueryRequest() { @@ -392,7 +392,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential .extractResponseContent(providerPendingIntentResponse .getResultData()); if (response != null && !mProviderResponseDataHandler.isEmptyResponse(response)) { - addToInitialRemoteResponse(response); + addToInitialRemoteResponse(response, /*isInitialResponse=*/ false); // Additional content received is in the form of new response content. return true; } @@ -400,7 +400,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return false; } - private void addToInitialRemoteResponse(BeginGetCredentialResponse content) { + private void addToInitialRemoteResponse(BeginGetCredentialResponse content, + boolean isInitialResponse) { if (content == null) { return; } @@ -408,7 +409,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential content.getCredentialEntries(), content.getActions(), content.getAuthenticationActions(), - content.getRemoteCredentialEntry() + content.getRemoteCredentialEntry(), + isInitialResponse ); } @@ -423,7 +425,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential /** Updates the response being maintained in state by this provider session. */ private void onSetInitialRemoteResponse(BeginGetCredentialResponse response) { mProviderResponse = response; - addToInitialRemoteResponse(response); + addToInitialRemoteResponse(response, /*isInitialResponse=*/true); if (mProviderResponseDataHandler.isEmptyResponse(response)) { updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE); return; @@ -462,7 +464,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential } private class ProviderResponseDataHandler { - private final ComponentName mExpectedRemoteEntryProviderService; + @Nullable private final ComponentName mExpectedRemoteEntryProviderService; @NonNull private final Map<String, Pair<CredentialEntry, Entry>> mUiCredentialEntries = new HashMap<>(); @@ -472,28 +474,35 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries = new HashMap<>(); - @Nullable private Pair<String, Pair<CredentialEntry, Entry>> mUiRemoteEntry = null; + @Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null; - ProviderResponseDataHandler(ComponentName expectedRemoteEntryProviderService) { + ProviderResponseDataHandler(@Nullable ComponentName expectedRemoteEntryProviderService) { mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService; } public void addResponseContent(List<CredentialEntry> credentialEntries, List<Action> actions, List<Action> authenticationActions, - CredentialEntry remoteEntry) { + RemoteEntry remoteEntry, boolean isInitialResponse) { credentialEntries.forEach(this::addCredentialEntry); actions.forEach(this::addAction); authenticationActions.forEach( authenticationAction -> addAuthenticationAction(authenticationAction, AuthenticationEntry.STATUS_LOCKED)); - setRemoteEntry(remoteEntry); + // In the query phase, it is likely most providers will return a null remote entry + // so no need to invoke the setter since it adds the overhead of checking for the + // hybrid permission, and then sets an already null value to null. + // If this is not the query phase, e.g. response after a locked entry is unlocked + // then it is valid for the provider to remove the remote entry, and so we allow + // them to set it to null. + if (remoteEntry != null || !isInitialResponse) { + setRemoteEntry(remoteEntry); + } } public void addCredentialEntry(CredentialEntry credentialEntry) { String id = generateUniqueId(); Entry entry = new Entry(CREDENTIAL_ENTRY_KEY, id, credentialEntry.getSlice(), - setUpFillInIntent(credentialEntry - .getBeginGetCredentialOption().getId())); + setUpFillInIntent(credentialEntry.getBeginGetCredentialOptionId())); mUiCredentialEntries.put(id, new Pair<>(credentialEntry, entry)); } @@ -522,22 +531,24 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential mUiAuthenticationEntries.remove(id); } - public void setRemoteEntry(@Nullable CredentialEntry remoteEntry) { - if (remoteEntry == null) { + public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) { + if (!enforceRemoteEntryRestrictions(mExpectedRemoteEntryProviderService)) { + Log.i(TAG, "Remote entry being dropped as it does not meet the restriction" + + " checks."); return; } - if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) { - Log.i(TAG, "Remote entry being dropped as it is not from the service " - + "configured by the OEM."); + if (remoteEntry == null) { + mUiRemoteEntry = null; return; } String id = generateUniqueId(); Entry entry = new Entry(REMOTE_ENTRY_KEY, - id, remoteEntry.getSlice(), setUpFillInIntent( - remoteEntry.getBeginGetCredentialOption().getId())); + id, remoteEntry.getSlice(), setUpFillInIntentForRemoteEntry()); mUiRemoteEntry = new Pair<>(generateUniqueId(), new Pair<>(remoteEntry, entry)); } + + public GetCredentialProviderData toGetCredentialProviderData() { return new GetCredentialProviderData.Builder( mComponentName.flattenToString()).setActionChips(prepareActionEntries()) @@ -571,7 +582,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential return credEntries; } - private Entry prepareRemoteEntry() { if (mUiRemoteEntry == null || mUiRemoteEntry.first == null || mUiRemoteEntry.second == null) { @@ -604,7 +614,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential } @Nullable - public CredentialEntry getRemoteEntry(String entryKey) { + public RemoteEntry getRemoteEntry(String entryKey) { return mUiRemoteEntry.first.equals(entryKey) && mUiRemoteEntry.second != null ? mUiRemoteEntry.second.first : null; } @@ -662,4 +672,10 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential from.getFrameworkExtrasIntent()); } } + + private Intent setUpFillInIntentForRemoteEntry() { + return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, + new GetCredentialRequest( + mCallingAppInfo, mCompleteRequest.getCredentialOptions())); + } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java index a57cb5fab0dc..36d6b3dc7636 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java @@ -121,7 +121,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption CredentialProviderService .EXTRA_GET_CREDENTIAL_REQUEST, new android.service.credentials.GetCredentialRequest( - mCallingAppInfo, mProviderRequest)); + mCallingAppInfo, List.of(mProviderRequest))); return intent; } diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java index ecddcf30f88d..53ed070e3e49 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java @@ -19,10 +19,13 @@ package com.android.server.credentials; import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_QUERY_FAILURE; import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_QUERY_SUCCESS; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.credentials.Credential; import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderPendingIntentResponse; @@ -228,6 +231,39 @@ public abstract class ProviderSession<T, R> return mProviderResponse; } + protected boolean enforceRemoteEntryRestrictions( + @Nullable ComponentName expectedRemoteEntryProviderService) { + // Check if the service is the one set by the OEM. If not silently reject this entry + if (!mComponentName.equals(expectedRemoteEntryProviderService)) { + Log.i(TAG, "Remote entry being dropped as it is not from the service " + + "configured by the OEM."); + return false; + } + // Check if the service has the hybrid permission .If not, silently reject this entry. + // This check is in addition to the permission check happening in the provider's process. + try { + ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo( + mComponentName.getPackageName(), + PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY)); + if (appInfo != null + && mContext.checkPermission( + Manifest.permission.PROVIDE_REMOTE_CREDENTIALS, + /*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) { + return true; + } + } catch (SecurityException e) { + Log.i(TAG, "Error getting info for " + + mComponentName.flattenToString() + ": " + e.getMessage()); + return false; + } catch (PackageManager.NameNotFoundException e) { + Log.i(TAG, "Error getting info for " + + mComponentName.flattenToString() + ": " + e.getMessage()); + return false; + } + Log.i(TAG, "In enforceRemoteEntryRestrictions - remote entry checks fail"); + return false; + } + /** Should be overridden to prepare, and stores state for {@link ProviderData} to be * shown on the UI. */ @Nullable protected abstract ProviderData prepareUiData(); diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index 702261ea43f5..ff4e3b680131 100644 --- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java +++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java @@ -121,8 +121,6 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr ProviderCallbacks<BeginGetCredentialResponse> callback) { Log.i(TAG, "In onGetCredentials in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); - AtomicReference<CompletableFuture<BeginGetCredentialResponse>> futureRef = - new AtomicReference<>(); CompletableFuture<BeginGetCredentialResponse> connectThenExecute = postAsync(service -> { CompletableFuture<BeginGetCredentialResponse> getCredentials = @@ -134,7 +132,6 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr new IBeginGetCredentialCallback.Stub() { @Override public void onSuccess(BeginGetCredentialResponse response) { - Log.i(TAG, "In onSuccess in RemoteCredentialService"); getCredentials.complete(response); } @@ -147,22 +144,15 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr new GetCredentialException(errorType, errorMsg)); } }); - CompletableFuture<BeginGetCredentialResponse> future = futureRef.get(); - if (future != null && future.isCancelled()) { - dispatchCancellationSignal(cancellationSignal); - } else { - cancellationSink.set(cancellationSignal); - } + cancellationSink.set(cancellationSignal); return getCredentials; } finally { Binder.restoreCallingIdentity(originalCallingUidToken); } }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS); - futureRef.set(connectThenExecute); connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); - return cancellationSink.get(); } @@ -178,8 +168,6 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr ProviderCallbacks<BeginCreateCredentialResponse> callback) { Log.i(TAG, "In onCreateCredential in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); - AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef = - new AtomicReference<>(); CompletableFuture<BeginCreateCredentialResponse> connectThenExecute = postAsync(service -> { @@ -205,19 +193,13 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr new CreateCredentialException(errorType, errorMsg)); } }); - CompletableFuture<BeginCreateCredentialResponse> future = futureRef.get(); - if (future != null && future.isCancelled()) { - dispatchCancellationSignal(cancellationSignal); - } else { - cancellationSink.set(cancellationSignal); - } + cancellationSink.set(cancellationSignal); return createCredentialFuture; } finally { Binder.restoreCallingIdentity(originalCallingUidToken); } }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS); - futureRef.set(connectThenExecute); connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); @@ -236,7 +218,6 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr ProviderCallbacks<Void> callback) { Log.i(TAG, "In onClearCredentialState in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); - AtomicReference<CompletableFuture<Void>> futureRef = new AtomicReference<>(); CompletableFuture<Void> connectThenExecute = postAsync(service -> { @@ -263,19 +244,13 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr errorMsg)); } }); - CompletableFuture<Void> future = futureRef.get(); - if (future != null && future.isCancelled()) { - dispatchCancellationSignal(cancellationSignal); - } else { - cancellationSink.set(cancellationSignal); - } + cancellationSink.set(cancellationSignal); return clearCredentialFuture; } finally { Binder.restoreCallingIdentity(originalCallingUidToken); } }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS); - futureRef.set(connectThenExecute); connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index f8bbfcfb6a4d..abfb2107c4a3 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -16,12 +16,7 @@ package com.android.server.credentials; -import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_CLEAR_CREDENTIAL; -import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_CREATE_CREDENTIAL; -import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_GET_CREDENTIAL; -import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_UNKNOWN; -import static com.android.server.credentials.MetricUtilities.METRICS_API_STATUS_FAILURE; -import static com.android.server.credentials.MetricUtilities.METRICS_API_STATUS_SUCCESS; +import static com.android.server.credentials.MetricUtilities.logApiCalled; import android.annotation.NonNull; import android.annotation.UserIdInt; @@ -39,7 +34,8 @@ import android.service.credentials.CredentialProviderInfo; import android.util.Log; import com.android.internal.R; -import com.android.internal.util.FrameworkStatsLog; +import com.android.server.credentials.metrics.ApiName; +import com.android.server.credentials.metrics.ApiStatus; import com.android.server.credentials.metrics.CandidateProviderMetric; import com.android.server.credentials.metrics.ChosenProviderMetric; @@ -82,7 +78,8 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan //TODO improve design to allow grouped metrics per request protected final String mHybridService; - @NonNull protected RequestSessionStatus mRequestSessionStatus = + @NonNull + protected RequestSessionStatus mRequestSessionStatus = RequestSessionStatus.IN_PROGRESS; /** The status in which a given request session is. */ @@ -162,50 +159,10 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan } return false; } - // TODO: move these definitions to a separate logging focused class. - enum RequestType { - GET_CREDENTIALS, - CREATE_CREDENTIALS, - CLEAR_CREDENTIALS, - } - - private static int getApiNameFromRequestType(RequestType requestType) { - switch (requestType) { - case GET_CREDENTIALS: - return METRICS_API_NAME_GET_CREDENTIAL; - case CREATE_CREDENTIALS: - return METRICS_API_NAME_CREATE_CREDENTIAL; - case CLEAR_CREDENTIALS: - return METRICS_API_NAME_CLEAR_CREDENTIAL; - default: - return METRICS_API_NAME_UNKNOWN; - } - } - protected void logApiCalled(RequestType requestType, boolean isSuccessfulOverall) { - var providerSessions = mProviders.values(); - int providerSize = providerSessions.size(); - int[] candidateUidList = new int[providerSize]; - int[] candidateQueryRoundTripTimeList = new int[providerSize]; - int[] candidateStatusList = new int[providerSize]; - int index = 0; - for (var session : providerSessions) { - CandidateProviderMetric metric = session.mCandidateProviderMetric; - candidateUidList[index] = metric.getCandidateUid(); - candidateQueryRoundTripTimeList[index] = metric.getQueryLatencyMs(); - candidateStatusList[index] = metric.getProviderQueryStatus(); - index++; - } - FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED, - /* api_name */getApiNameFromRequestType(requestType), /* caller_uid */ - mCallingUid, /* api_status */ - isSuccessfulOverall ? METRICS_API_STATUS_SUCCESS : METRICS_API_STATUS_FAILURE, - candidateUidList, - candidateQueryRoundTripTimeList, - candidateStatusList, mChosenProviderMetric.getChosenUid(), - mChosenProviderMetric.getEntireProviderLatencyMs(), - mChosenProviderMetric.getFinalPhaseLatencyMs(), - mChosenProviderMetric.getChosenProviderStatus()); + protected void logApiCall(ApiName apiName, ApiStatus apiStatus) { + logApiCalled(apiName, apiStatus, mProviders, mCallingUid, + mChosenProviderMetric); } protected boolean isSessionCancelled() { @@ -257,6 +214,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan /** * Called by RequestSession's upon chosen metric determination. + * * @param componentName the componentName to associate with a provider */ protected void setChosenMetric(ComponentName componentName) { @@ -264,8 +222,8 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan .mCandidateProviderMetric; mChosenProviderMetric.setChosenUid(metric.getCandidateUid()); mChosenProviderMetric.setFinalFinishTimeNanoseconds(System.nanoTime()); - mChosenProviderMetric.setQueryFinishTimeNanoseconds( - metric.getQueryFinishTimeNanoseconds()); - mChosenProviderMetric.setStartTimeNanoseconds(metric.getStartTimeNanoseconds()); + mChosenProviderMetric.setQueryPhaseLatencyMicroseconds( + metric.getQueryLatencyMicroseconds()); + mChosenProviderMetric.setQueryStartTimeNanoseconds(metric.getStartQueryTimeNanoseconds()); } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java new file mode 100644 index 000000000000..d4b51dfcc299 --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java @@ -0,0 +1,48 @@ +/* + * 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.credentials.metrics; + +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN; + +public enum ApiName { + UNKNOWN(CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN), + GET_CREDENTIAL(CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL), + CREATE_CREDENTIAL(CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL), + CLEAR_CREDENTIAL(CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL), + IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE( + CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE + ); + + private final int mInnerMetricCode; + + ApiName(int innerMetricCode) { + this.mInnerMetricCode = innerMetricCode; + } + + /** + * Gives the West-world version of the metric name. + * + * @return a code corresponding to the west world metric name + */ + public int getMetricCode() { + return this.mInnerMetricCode; + } +} diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java b/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java new file mode 100644 index 000000000000..36a1f2df6d24 --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java @@ -0,0 +1,46 @@ +/* + * 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.credentials.metrics; + +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_CLIENT_CANCELED; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS; +import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_USER_CANCELED; + +public enum ApiStatus { + METRICS_API_STATUS_SUCCESS(CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS), + METRICS_API_STATUS_FAILURE(CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE), + METRICS_API_STATUS_CLIENT_CANCELED( + CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_CLIENT_CANCELED), + METRICS_API_STATUS_USER_CANCELED( + CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_USER_CANCELED); + + private final int mInnerMetricCode; + + ApiStatus(int innerMetricCode) { + this.mInnerMetricCode = innerMetricCode; + } + + /** + * Gives the West-world version of the metric name. + * + * @return a code corresponding to the west world metric name + */ + public int getMetricCode() { + return this.mInnerMetricCode; + } +} diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java index acfb4a4e3e39..f49995d041aa 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java @@ -18,63 +18,69 @@ package com.android.server.credentials.metrics; /** * The central candidate provider metric object that mimics our defined metric setup. + * TODO(b/270403549) - iterate on this in V3+ */ public class CandidateProviderMetric { + private static final String TAG = "CandidateProviderMetric"; private int mCandidateUid = -1; - private long mStartTimeNanoseconds = -1; + + // Raw timestamp in nanoseconds, will be converted to microseconds for logging + + private long mStartQueryTimeNanoseconds = -1; private long mQueryFinishTimeNanoseconds = -1; private int mProviderQueryStatus = -1; - public CandidateProviderMetric(long startTime, long queryFinishTime, int providerQueryStatus, - int candidateUid) { - this.mStartTimeNanoseconds = startTime; - this.mQueryFinishTimeNanoseconds = queryFinishTime; - this.mProviderQueryStatus = providerQueryStatus; - this.mCandidateUid = candidateUid; + public CandidateProviderMetric() { } - public CandidateProviderMetric(){} + /* ---------- Latencies ---------- */ - public void setStartTimeNanoseconds(long startTimeNanoseconds) { - this.mStartTimeNanoseconds = startTimeNanoseconds; + public void setStartQueryTimeNanoseconds(long startQueryTimeNanoseconds) { + this.mStartQueryTimeNanoseconds = startQueryTimeNanoseconds; } public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) { this.mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds; } - public void setProviderQueryStatus(int providerQueryStatus) { - this.mProviderQueryStatus = providerQueryStatus; + public long getStartQueryTimeNanoseconds() { + return this.mStartQueryTimeNanoseconds; } - public void setCandidateUid(int candidateUid) { - this.mCandidateUid = candidateUid; + public long getQueryFinishTimeNanoseconds() { + return this.mQueryFinishTimeNanoseconds; } - public long getStartTimeNanoseconds() { - return this.mStartTimeNanoseconds; + /** + * Returns the latency in microseconds for the query phase. + */ + public int getQueryLatencyMicroseconds() { + return (int) ((this.getQueryFinishTimeNanoseconds() + - this.getStartQueryTimeNanoseconds()) / 1000); } - public long getQueryFinishTimeNanoseconds() { - return this.mQueryFinishTimeNanoseconds; + // TODO (in direct next dependent CL, so this is transient) - add reference timestamp in micro + // seconds for this too. + + /* ------------- Provider Query Status ------------ */ + + public void setProviderQueryStatus(int providerQueryStatus) { + this.mProviderQueryStatus = providerQueryStatus; } public int getProviderQueryStatus() { return this.mProviderQueryStatus; } - public int getCandidateUid() { - return this.mCandidateUid; - } + /* -------------- Candidate Uid ---------------- */ - /** - * Returns the latency in microseconds for the query phase. - */ - public int getQueryLatencyMs() { - return (int) ((this.getQueryFinishTimeNanoseconds() - - this.getStartTimeNanoseconds()) / 1000); + public void setCandidateUid(int candidateUid) { + this.mCandidateUid = candidateUid; } + public int getCandidateUid() { + return this.mCandidateUid; + } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java index c4d0b3c7254d..75fdc567013c 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java @@ -16,18 +16,39 @@ package com.android.server.credentials.metrics; +import android.util.Log; + +import com.android.server.credentials.MetricUtilities; + /** * The central chosen provider metric object that mimics our defined metric setup. + * TODO(b/270403549) - iterate on this in V3+ */ public class ChosenProviderMetric { + // TODO(b/270403549) - applies elsewhere, likely removed or replaced with a count-index (1,2,3) + private static final String TAG = "ChosenProviderMetric"; private int mChosenUid = -1; - private long mStartTimeNanoseconds = -1; - private long mQueryFinishTimeNanoseconds = -1; + + // Latency figures typically fed in from prior CandidateProviderMetric + + private int mPreQueryPhaseLatencyMicroseconds = -1; + private int mQueryPhaseLatencyMicroseconds = -1; + + // Timestamps kept in raw nanoseconds. Expected to be converted to microseconds from using + // reference 'mServiceBeganTimeNanoseconds' during metric log point. + + private long mServiceBeganTimeNanoseconds = -1; + private long mQueryStartTimeNanoseconds = -1; + private long mUiCallStartTimeNanoseconds = -1; + private long mUiCallEndTimeNanoseconds = -1; private long mFinalFinishTimeNanoseconds = -1; private int mChosenProviderStatus = -1; - public ChosenProviderMetric() {} + public ChosenProviderMetric() { + } + + /* ------------------- UID ------------------- */ public int getChosenUid() { return mChosenUid; @@ -37,54 +58,145 @@ public class ChosenProviderMetric { mChosenUid = chosenUid; } - public long getStartTimeNanoseconds() { - return mStartTimeNanoseconds; + /* ---------------- Latencies ------------------ */ + + + /* ----- Direct Latencies ------- */ + + /** + * In order for a chosen provider to be selected, the call must have successfully begun. + * Thus, the {@link PreCandidateMetric} can directly pass this initial latency figure into + * this chosen provider metric. + * + * @param preQueryPhaseLatencyMicroseconds the millisecond latency for the service start, + * typically passed in through the + * {@link PreCandidateMetric} + */ + public void setPreQueryPhaseLatencyMicroseconds(int preQueryPhaseLatencyMicroseconds) { + mPreQueryPhaseLatencyMicroseconds = preQueryPhaseLatencyMicroseconds; } - public void setStartTimeNanoseconds(long startTimeNanoseconds) { - mStartTimeNanoseconds = startTimeNanoseconds; + /** + * In order for a chosen provider to be selected, a candidate provider must exist. The + * candidate provider can directly pass the final latency figure into this chosen provider + * metric. + * + * @param queryPhaseLatencyMicroseconds the millisecond latency for the query phase, typically + * passed in through the {@link CandidateProviderMetric} + */ + public void setQueryPhaseLatencyMicroseconds(int queryPhaseLatencyMicroseconds) { + mQueryPhaseLatencyMicroseconds = queryPhaseLatencyMicroseconds; } - public long getQueryFinishTimeNanoseconds() { - return mQueryFinishTimeNanoseconds; + public int getPreQueryPhaseLatencyMicroseconds() { + return mPreQueryPhaseLatencyMicroseconds; } - public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) { - mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds; + public int getQueryPhaseLatencyMicroseconds() { + return mQueryPhaseLatencyMicroseconds; } - public long getFinalFinishTimeNanoseconds() { - return mFinalFinishTimeNanoseconds; + public int getUiPhaseLatencyMicroseconds() { + return (int) ((this.mUiCallEndTimeNanoseconds + - this.mUiCallStartTimeNanoseconds) / 1000); + } + + /** + * Returns the full provider (invocation to response) latency in microseconds. Expects the + * start time to be provided, such as from {@link CandidateProviderMetric}. + */ + public int getEntireProviderLatencyMicroseconds() { + return (int) ((this.mFinalFinishTimeNanoseconds + - this.mQueryStartTimeNanoseconds) / 1000); + } + + /** + * Returns the full (platform invoked to response) latency in microseconds. Expects the + * start time to be provided, such as from {@link PreCandidateMetric}. + */ + public int getEntireLatencyMicroseconds() { + return (int) ((this.mFinalFinishTimeNanoseconds + - this.mServiceBeganTimeNanoseconds) / 1000); + } + + /* ----- Timestamps for Latency ----- */ + + /** + * In order for a chosen provider to be selected, the call must have successfully begun. + * Thus, the {@link PreCandidateMetric} can directly pass this initial timestamp into this + * chosen provider metric. + * + * @param serviceBeganTimeNanoseconds the timestamp moment when the platform was called, + * typically passed in through the {@link PreCandidateMetric} + */ + public void setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds) { + mServiceBeganTimeNanoseconds = serviceBeganTimeNanoseconds; + } + + public void setQueryStartTimeNanoseconds(long queryStartTimeNanoseconds) { + mQueryStartTimeNanoseconds = queryStartTimeNanoseconds; + } + + public void setUiCallStartTimeNanoseconds(long uiCallStartTimeNanoseconds) { + this.mUiCallStartTimeNanoseconds = uiCallStartTimeNanoseconds; + } + + public void setUiCallEndTimeNanoseconds(long uiCallEndTimeNanoseconds) { + this.mUiCallEndTimeNanoseconds = uiCallEndTimeNanoseconds; } public void setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds) { mFinalFinishTimeNanoseconds = finalFinishTimeNanoseconds; } - public int getChosenProviderStatus() { - return mChosenProviderStatus; + public long getServiceBeganTimeNanoseconds() { + return mServiceBeganTimeNanoseconds; } - public void setChosenProviderStatus(int chosenProviderStatus) { - mChosenProviderStatus = chosenProviderStatus; + public long getQueryStartTimeNanoseconds() { + return mQueryStartTimeNanoseconds; } - /** - * Returns the full provider (invocation to response) latency in microseconds. - */ - public int getEntireProviderLatencyMs() { - return (int) ((this.getFinalFinishTimeNanoseconds() - - this.getStartTimeNanoseconds()) / 1000); + public long getUiCallStartTimeNanoseconds() { + return mUiCallStartTimeNanoseconds; } - // TODO get post click final phase and re-add the query phase time to metric + public long getUiCallEndTimeNanoseconds() { + return mUiCallEndTimeNanoseconds; + } + + public long getFinalFinishTimeNanoseconds() { + return mFinalFinishTimeNanoseconds; + } + + /* --- Time Stamp Conversion to Microseconds --- */ /** - * Returns the end of query to response phase latency in microseconds. + * We collect raw timestamps in nanoseconds for ease of collection. However, given the scope + * of our logging timeframe, and size considerations of the metric, we require these to give us + * the microsecond timestamps from the start reference point. + * + * @param specificTimestamp the timestamp to consider, must be greater than the reference + * @return the microsecond integer timestamp from service start to query began */ - public int getFinalPhaseLatencyMs() { - return (int) ((this.getFinalFinishTimeNanoseconds() - - this.getQueryFinishTimeNanoseconds()) / 1000); + public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) { + if (specificTimestamp < this.mServiceBeganTimeNanoseconds) { + Log.i(TAG, "The timestamp is before service started, falling back to default int"); + return MetricUtilities.DEFAULT_INT_32; + } + return (int) ((specificTimestamp + - this.mServiceBeganTimeNanoseconds) / 1000); + } + + + + /* ----------- Provider Status -------------- */ + + public int getChosenProviderStatus() { + return mChosenProviderStatus; } + public void setChosenProviderStatus(int chosenProviderStatus) { + mChosenProviderStatus = chosenProviderStatus; + } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/PreCandidateMetric.java b/services/credentials/java/com/android/server/credentials/metrics/PreCandidateMetric.java new file mode 100644 index 000000000000..952328f6ba3a --- /dev/null +++ b/services/credentials/java/com/android/server/credentials/metrics/PreCandidateMetric.java @@ -0,0 +1,65 @@ +/* + * 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.credentials.metrics; + +/** + * This handles metrics collected prior to any remote calls to providers. + * TODO(b/270403549) - iterate on this in V3+ + */ +public class PreCandidateMetric { + + private static final String TAG = "PreCandidateMetric"; + + // Raw timestamps in nanoseconds, *the only* one logged as such (i.e. 64 bits) since it is a + // reference point. + + private long mCredentialServiceStartedTimeNanoseconds = -1; + private long mCredentialServiceBeginQueryTimeNanoseconds = -1; + + public PreCandidateMetric() { + } + + /* ---------- Latencies ---------- */ + + /* -- Direct Latencies -- */ + + public int getServiceStartToQueryLatencyMicroseconds() { + return (int) ((this.mCredentialServiceStartedTimeNanoseconds + - this.mCredentialServiceBeginQueryTimeNanoseconds) / 1000); + } + + /* -- Timestamps -- */ + + public void setCredentialServiceStartedTimeNanoseconds( + long credentialServiceStartedTimeNanoseconds + ) { + this.mCredentialServiceStartedTimeNanoseconds = credentialServiceStartedTimeNanoseconds; + } + + public void setCredentialServiceBeginQueryTimeNanoseconds( + long credentialServiceBeginQueryTimeNanoseconds) { + mCredentialServiceBeginQueryTimeNanoseconds = credentialServiceBeginQueryTimeNanoseconds; + } + + public long getCredentialServiceStartedTimeNanoseconds() { + return mCredentialServiceStartedTimeNanoseconds; + } + + public long getCredentialServiceBeginQueryTimeNanoseconds() { + return mCredentialServiceBeginQueryTimeNanoseconds; + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2357b38e434c..a4e563b21bec 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3212,8 +3212,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void sendChangedNotification(int userHandle) { Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + Bundle options = new BroadcastOptions() + .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) + .setDeferUntilActive(true) + .toBundle(); mInjector.binderWithCleanCallingIdentity(() -> - mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle))); + mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle), null, options)); } private void loadSettingsLocked(DevicePolicyData policy, int userHandle) { @@ -11356,7 +11360,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_APPLICATION_RESTRICTIONS) .setAdmin(caller.getPackageName()) - .setBoolean(/* isDelegate */ who == null) + .setBoolean(/* isDelegate */ isCallerDelegate(caller)) .setStrings(packageName) .write(); } @@ -13397,7 +13401,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_APPLICATION_HIDDEN) .setAdmin(caller.getPackageName()) - .setBoolean(/* isDelegate */ who == null) + .setBoolean(/* isDelegate */ isCallerDelegate(caller)) .setStrings(packageName, hidden ? "hidden" : "not_hidden", parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT) .write(); @@ -13749,7 +13753,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_UNINSTALL_BLOCKED) .setAdmin(caller.getPackageName()) - .setBoolean(/* isDelegate */ who == null) + .setBoolean(/* isDelegate */ isCallerDelegate(caller)) .setStrings(packageName) .write(); } @@ -16299,7 +16303,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .setAdmin(caller.getPackageName()) .setStrings(permission) .setInt(grantState) - .setBoolean(/* isDelegate */ admin == null) + .setBoolean( + /* isDelegate */ isCallerDelegate(caller)) .write(); callback.sendResult(Bundle.EMPTY); @@ -16424,12 +16429,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mInjector.getPackageManager().getPackagesForUid(caller.getUid())); Preconditions.checkArgument(callerUidPackageNames.contains(packageName), "Caller uid doesn't match the one for the provided package."); + + return checkProvisioningPreconditionSkipPermission(action, packageName, caller.getUserId()) + == STATUS_OK; } finally { mInjector.binderRestoreCallingIdentity(ident); } - - return checkProvisioningPreconditionSkipPermission(action, packageName, caller.getUserId()) - == STATUS_OK; } @Override @@ -22202,6 +22207,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>(); { DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, DELEGATION_PERMISSION_GRANT); + DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, DELEGATION_APP_RESTRICTIONS); + DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APPS_CONTROL, DELEGATION_BLOCK_UNINSTALL); + DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, DELEGATION_SECURITY_LOGGING); + DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE, DELEGATION_PACKAGE_ACCESS); } private static final HashMap<String, String> CROSS_USER_PERMISSIONS = @@ -22390,6 +22399,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + permission + ", " + CROSS_USER_PERMISSIONS.get(permission) + + "(if calling cross-user)" + "}"); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 850b5b686efe..edfe95efe7f9 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -2739,6 +2739,14 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); + t.traceBegin("RegisterLogMteState"); + try { + LogMteState.register(context); + } catch (Throwable e) { + reportWtf("RegisterLogMteState", e); + } + t.traceEnd(); + // Emit any pending system_server WTFs synchronized (SystemService.class) { if (sPendingWtfs != null) { diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index 17e1744d85ab..0ca4dfced1b6 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -113,7 +113,6 @@ public class DataManager { private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L; @VisibleForTesting static final int MAX_CACHED_RECENT_SHORTCUTS = 30; - private static final int DEBOUNCE_LENGTH_MS = 500; private final Context mContext; private final Injector mInjector; @@ -130,7 +129,6 @@ public class DataManager { private final List<PeopleService.ConversationsListener> mConversationsListeners = new ArrayList<>(1); private final Handler mHandler; - private final PerPackageThrottler mShortcutsThrottler; private ContentObserver mCallLogContentObserver; private ContentObserver mMmsSmsContentObserver; @@ -142,17 +140,14 @@ public class DataManager { private ConversationStatusExpirationBroadcastReceiver mStatusExpReceiver; public DataManager(Context context) { - this(context, new Injector(), BackgroundThread.get().getLooper(), - new PerPackageThrottlerImpl(BackgroundThread.getHandler(), DEBOUNCE_LENGTH_MS)); + this(context, new Injector(), BackgroundThread.get().getLooper()); } - DataManager(Context context, Injector injector, Looper looper, - PerPackageThrottler shortcutsThrottler) { + DataManager(Context context, Injector injector, Looper looper) { mContext = context; mInjector = injector; mScheduledExecutor = mInjector.createScheduledExecutor(); mHandler = new Handler(looper); - mShortcutsThrottler = shortcutsThrottler; } /** Initialization. Called when the system services are up running. */ @@ -856,12 +851,12 @@ public class DataManager { // pair of <package name, conversation info> List<Pair<String, ConversationInfo>> cachedConvos = new ArrayList<>(); userData.forAllPackages(packageData -> { - packageData.forAllConversations(conversationInfo -> { - if (isEligibleForCleanUp(conversationInfo)) { - cachedConvos.add( - Pair.create(packageData.getPackageName(), conversationInfo)); - } - }); + packageData.forAllConversations(conversationInfo -> { + if (isEligibleForCleanUp(conversationInfo)) { + cachedConvos.add( + Pair.create(packageData.getPackageName(), conversationInfo)); + } + }); }); if (cachedConvos.size() <= targetCachedCount) { return; @@ -872,8 +867,8 @@ public class DataManager { numToUncache + 1, Comparator.comparingLong((Pair<String, ConversationInfo> pair) -> Math.max( - pair.second.getLastEventTimestamp(), - pair.second.getCreationTimestamp())).reversed()); + pair.second.getLastEventTimestamp(), + pair.second.getCreationTimestamp())).reversed()); for (Pair<String, ConversationInfo> cached : cachedConvos) { if (hasActiveNotifications(cached.first, userId, cached.second.getShortcutId())) { continue; @@ -1109,35 +1104,26 @@ public class DataManager { @Override public void onShortcutsAddedOrUpdated(@NonNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) { - mShortcutsThrottler.scheduleDebounced( - new Pair<>(packageName, user.getIdentifier()), - () -> { - PackageData packageData = getPackage(packageName, user.getIdentifier()); - List<ShortcutInfo> queriedShortcuts = getShortcuts(packageName, - user.getIdentifier(), null); - boolean hasCachedShortcut = false; - for (ShortcutInfo shortcut : queriedShortcuts) { - if (ShortcutHelper.isConversationShortcut( - shortcut, mShortcutServiceInternal, user.getIdentifier())) { - if (shortcut.isCached()) { - ConversationInfo info = packageData != null - ? packageData.getConversationInfo(shortcut.getId()) - : null; - if (info == null - || !info.isShortcutCachedForNotification()) { - hasCachedShortcut = true; - } - } - addOrUpdateConversationInfo(shortcut); + mInjector.getBackgroundExecutor().execute(() -> { + PackageData packageData = getPackage(packageName, user.getIdentifier()); + for (ShortcutInfo shortcut : shortcuts) { + if (ShortcutHelper.isConversationShortcut( + shortcut, mShortcutServiceInternal, user.getIdentifier())) { + if (shortcut.isCached()) { + ConversationInfo conversationInfo = packageData != null + ? packageData.getConversationInfo(shortcut.getId()) : null; + if (conversationInfo == null + || !conversationInfo.isShortcutCachedForNotification()) { + // This is a newly cached shortcut. Clean up the existing cached + // shortcuts to ensure the cache size is under the limit. + cleanupCachedShortcuts(user.getIdentifier(), + MAX_CACHED_RECENT_SHORTCUTS - 1); } } - // Added at least one new conversation. Uncache older existing cached - // shortcuts to ensure the cache size is under the limit. - if (hasCachedShortcut) { - cleanupCachedShortcuts(user.getIdentifier(), - MAX_CACHED_RECENT_SHORTCUTS); - } - }); + addOrUpdateConversationInfo(shortcut); + } + } + }); } @Override diff --git a/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java b/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java deleted file mode 100644 index fa5a67b328b2..000000000000 --- a/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.people.data; - -import android.os.Handler; -import android.util.Pair; - -import java.util.HashSet; - -/** - * A class that implements a per-package throttler that prevents a runnable from executing more than - * once every {@code debounceTime}. - */ -public class PerPackageThrottlerImpl implements PerPackageThrottler { - private final Handler mBackgroundHandler; - private final int mDebounceTime; - private final HashSet<Pair<String, Integer>> mPkgScheduledTasks = new HashSet<>(); - - PerPackageThrottlerImpl(Handler backgroundHandler, int debounceTime) { - mBackgroundHandler = backgroundHandler; - mDebounceTime = debounceTime; - } - - @Override - public synchronized void scheduleDebounced( - Pair<String, Integer> pkgUserId, Runnable runnable) { - if (mPkgScheduledTasks.contains(pkgUserId)) { - return; - } - mPkgScheduledTasks.add(pkgUserId); - mBackgroundHandler.postDelayed(() -> { - synchronized (this) { - mPkgScheduledTasks.remove(pkgUserId); - runnable.run(); - } - }, mDebounceTime); - } -} diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java index a39e0216f4e5..836f8581e8eb 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -566,6 +566,22 @@ public class PackageManagerSettingsTests { } @Test + public void testWriteCorruptReadPackageRestrictions() { + final Settings settingsUnderTest = makeSettings(); + + populateDistractionFlags(settingsUnderTest); + settingsUnderTest.writePackageRestrictionsLPr(0, /*sync=*/true); + + // Corrupt primary file. + writeCorruptedPackageRestrictions(0); + + // now read and verify + populateDefaultSettings(settingsUnderTest); + settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes); + verifyDistractionFlags(settingsUnderTest); + } + + @Test public void testReadWritePackageRestrictionsAsync() { final Settings settingsWrite = makeSettings(); final Settings settingsRead = makeSettings(); @@ -1811,6 +1827,14 @@ public class PackageManagerSettingsTests { .getBytes()); } + private void writeCorruptedPackageRestrictions(final int userId) { + writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/users/" + + userId + "/package-restrictions.xml"), + ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + + "<package-restrictions>\n" + + " <pkg name=\"" + PACKAGE_NAME_1 + "\" ").getBytes()); + } + private static void writeStoppedPackagesXml() { writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"), ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index bcd69fda8c28..85820127d36c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -86,6 +86,9 @@ import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.SystemClock; import android.provider.DeviceConfig; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.telephony.emergency.EmergencyNumber; import androidx.test.runner.AndroidJUnit4; @@ -119,6 +122,8 @@ public class DeviceIdleControllerTest { private AnyMotionDetectorForTest mAnyMotionDetector; private AppStateTrackerForTest mAppStateTracker; private DeviceIdleController.Constants mConstants; + private TelephonyCallback.OutgoingEmergencyCallListener mEmergencyCallListener; + private TelephonyCallback.CallStateListener mCallStateListener; private InjectorForTest mInjector; private MockitoSession mMockingSession; @@ -140,6 +145,8 @@ public class DeviceIdleControllerTest { private Sensor mMotionSensor; @Mock private SensorManager mSensorManager; + @Mock + private TelephonyManager mTelephonyManager; class InjectorForTest extends DeviceIdleController.Injector { ConnectivityManager connectivityManager; @@ -232,6 +239,11 @@ public class DeviceIdleControllerTest { } @Override + TelephonyManager getTelephonyManager() { + return mTelephonyManager; + } + + @Override boolean useMotionSensor() { return true; } @@ -343,6 +355,15 @@ public class DeviceIdleControllerTest { // Get the same Constants object that mDeviceIdleController got. mConstants = mInjector.getConstants(mDeviceIdleController); + + final ArgumentCaptor<TelephonyCallback> telephonyCallbackCaptor = + ArgumentCaptor.forClass(TelephonyCallback.class); + verify(mTelephonyManager) + .registerTelephonyCallback(any(), telephonyCallbackCaptor.capture()); + mEmergencyCallListener = (TelephonyCallback.OutgoingEmergencyCallListener) + telephonyCallbackCaptor.getValue(); + mCallStateListener = + (TelephonyCallback.CallStateListener) telephonyCallbackCaptor.getValue(); } @After @@ -531,6 +552,16 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_ACTIVE); + + // All other conditions allow for going INACTIVE... + setAlarmSoon(false); + setChargingOn(false); + setScreenOn(false); + // ...except the emergency call. + setEmergencyCallActive(true); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyStateConditions(STATE_ACTIVE); } @Test @@ -559,6 +590,15 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + // All other conditions allow for going INACTIVE... + setChargingOn(false); + setScreenOn(false); + // ...except the emergency call. + setEmergencyCallActive(true); + + mDeviceIdleController.becomeInactiveIfAppropriateLocked(); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); } @Test @@ -569,6 +609,7 @@ public class DeviceIdleControllerTest { setAlarmSoon(false); setChargingOn(false); setScreenOn(false); + setEmergencyCallActive(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyStateConditions(STATE_INACTIVE); @@ -613,6 +654,7 @@ public class DeviceIdleControllerTest { setChargingOn(false); setScreenOn(false); + setEmergencyCallActive(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); verifyLightStateConditions(LIGHT_STATE_INACTIVE); @@ -1147,6 +1189,22 @@ public class DeviceIdleControllerTest { eq(true)); } + @Test + public void testEmergencyCallEndTriggersInactive() { + setAlarmSoon(false); + setChargingOn(false); + setScreenOn(false); + setEmergencyCallActive(true); + + verifyStateConditions(STATE_ACTIVE); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + setEmergencyCallActive(false); + + verifyStateConditions(STATE_INACTIVE); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + } + ///////////////// EXIT conditions /////////////////// @Test @@ -2096,6 +2154,75 @@ public class DeviceIdleControllerTest { .onDeviceStationaryChanged(eq(true)); } + @Test + public void testEmergencyEndsIdle() { + enterDeepState(STATE_ACTIVE); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_INACTIVE); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_IDLE_PENDING); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_SENSING); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_LOCATING); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + // Quick doze enabled or not shouldn't affect the end state. + enterDeepState(STATE_QUICK_DOZE_DELAY); + setQuickDozeEnabled(true); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_QUICK_DOZE_DELAY); + setQuickDozeEnabled(false); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_IDLE); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + + enterDeepState(STATE_IDLE_MAINTENANCE); + setEmergencyCallActive(true); + verifyStateConditions(STATE_ACTIVE); + } + + @Test + public void testEmergencyEndsLightIdle() { + enterLightState(LIGHT_STATE_ACTIVE); + setEmergencyCallActive(true); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + enterLightState(LIGHT_STATE_INACTIVE); + setEmergencyCallActive(true); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + enterLightState(LIGHT_STATE_WAITING_FOR_NETWORK); + setEmergencyCallActive(true); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + enterLightState(LIGHT_STATE_IDLE); + setEmergencyCallActive(true); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + enterLightState(LIGHT_STATE_IDLE_MAINTENANCE); + setEmergencyCallActive(true); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + + enterLightState(LIGHT_STATE_OVERRIDE); + setEmergencyCallActive(true); + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + } + private void enterDeepState(int state) { switch (state) { case STATE_ACTIVE: @@ -2108,6 +2235,7 @@ public class DeviceIdleControllerTest { setQuickDozeEnabled(true); setScreenOn(false); setChargingOn(false); + setEmergencyCallActive(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); break; case STATE_LOCATING: @@ -2128,6 +2256,7 @@ public class DeviceIdleControllerTest { setQuickDozeEnabled(false); setScreenOn(false); setChargingOn(false); + setEmergencyCallActive(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); int count = 0; while (mDeviceIdleController.getState() != state) { @@ -2159,6 +2288,7 @@ public class DeviceIdleControllerTest { enterLightState(LIGHT_STATE_ACTIVE); setScreenOn(false); setChargingOn(false); + setEmergencyCallActive(false); int count = 0; mDeviceIdleController.becomeInactiveIfAppropriateLocked(); while (mDeviceIdleController.getLightState() != lightState) { @@ -2177,6 +2307,7 @@ public class DeviceIdleControllerTest { case LIGHT_STATE_OVERRIDE: setScreenOn(false); setChargingOn(false); + setEmergencyCallActive(false); mDeviceIdleController.setLightStateForTest(lightState); break; default: @@ -2188,6 +2319,14 @@ public class DeviceIdleControllerTest { mDeviceIdleController.updateChargingLocked(on); } + private void setEmergencyCallActive(boolean active) { + if (active) { + mEmergencyCallListener.onOutgoingEmergencyCall(mock(EmergencyNumber.class), 0); + } else { + mCallStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE); + } + } + private void setScreenLocked(boolean locked) { mDeviceIdleController.keyguardShowingLocked(locked); } @@ -2235,6 +2374,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; case STATE_IDLE_PENDING: assertEquals( @@ -2244,6 +2384,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; case STATE_SENSING: assertEquals( @@ -2255,6 +2396,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; case STATE_LOCATING: assertEquals( @@ -2263,6 +2405,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; case STATE_IDLE: if (mDeviceIdleController.hasMotionSensor()) { @@ -2276,6 +2419,7 @@ public class DeviceIdleControllerTest { && !mDeviceIdleController.isKeyguardShowing()); // Light state should be OVERRIDE at this point. verifyLightStateConditions(LIGHT_STATE_OVERRIDE); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; case STATE_IDLE_MAINTENANCE: if (mDeviceIdleController.hasMotionSensor()) { @@ -2287,6 +2431,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; case STATE_QUICK_DOZE_DELAY: // If quick doze is enabled, the motion listener should NOT be active. @@ -2295,6 +2440,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; default: fail("Conditions for " + stateToString(expectedState) + " unknown."); @@ -2312,6 +2458,7 @@ public class DeviceIdleControllerTest { case LIGHT_STATE_ACTIVE: assertTrue( mDeviceIdleController.isCharging() || mDeviceIdleController.isScreenOn() + || mDeviceIdleController.isEmergencyCallActive() // Or there's an alarm coming up soon. || SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM > mAlarmManager.getNextWakeFromIdleTime()); @@ -2324,6 +2471,7 @@ public class DeviceIdleControllerTest { assertFalse(mDeviceIdleController.isCharging()); assertFalse(mDeviceIdleController.isScreenOn() && !mDeviceIdleController.isKeyguardShowing()); + assertFalse(mDeviceIdleController.isEmergencyCallActive()); break; default: fail("Conditions for " + lightStateToString(expectedLightState) + " unknown."); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 99da415380cd..8a5d3a6772a5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -558,7 +558,7 @@ public final class BroadcastQueueModernImplTest { // To maximize test coverage, dump current state; we're not worried // about the actual output, just that we don't crash - queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED); + queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED, "Test-driven"); queue.dumpLocked(SystemClock.uptimeMillis(), new IndentingPrintWriter(new PrintWriter(new ByteArrayOutputStream()))); 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 485ce33dfb7d..0b4c70c285c1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -1968,6 +1968,36 @@ public class MockingOomAdjusterTests { @SuppressWarnings("GuardedBy") @Test + public void testUpdateOomAdj_DoOne_PendingFinishAttach() { + ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); + app.setPendingFinishAttach(true); + app.mState.setHasForegroundActivities(false); + + sService.mOomAdjuster.setAttachingProcessStatesLSP(app); + updateOomAdj(app); + + assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ, + SCHED_GROUP_DEFAULT); + } + + @SuppressWarnings("GuardedBy") + @Test + public void testUpdateOomAdj_DoOne_TopApp_PendingFinishAttach() { + ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); + app.setPendingFinishAttach(true); + app.mState.setHasForegroundActivities(true); + + sService.mOomAdjuster.setAttachingProcessStatesLSP(app); + updateOomAdj(app); + + assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ, + SCHED_GROUP_TOP_APP); + } + + @SuppressWarnings("GuardedBy") + @Test public void testUpdateOomAdj_UidIdle_StopService() { final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); 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 3e0e5a8414dd..7942e246c2a7 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -249,7 +249,7 @@ public final class DisplayPowerController2Test { when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn( - DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID); + DisplayDeviceConfig.DEFAULT_ID); when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock); 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 6c4afd37d8b1..16bf2a227c8a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -252,7 +252,7 @@ public final class DisplayPowerControllerTest { when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn( - DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID); + DisplayDeviceConfig.DEFAULT_ID); when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java index 9aa53db6fe1b..8979585d9235 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java @@ -20,6 +20,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE; +import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE; +import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible; import static com.android.server.pm.UserVisibilityChangedEvent.onVisible; @@ -73,8 +75,8 @@ public final class UserVisibilityMediatorMUPANDTest assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); // Make sure another user cannot be started on default display - int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId, - BG_VISIBLE, DEFAULT_DISPLAY); + int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE, + DEFAULT_DISPLAY); assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, "when user (%d) is starting on default display after it was started by user %d", otherUserId, visibleBgUserId); @@ -117,8 +119,8 @@ public final class UserVisibilityMediatorMUPANDTest assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID); // Make sure another user cannot be started on default display - int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId, - BG_VISIBLE, DEFAULT_DISPLAY); + int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE, + DEFAULT_DISPLAY); assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE, "when user (%d) is starting on default display after it was started by user %d", otherUserId, visibleBgUserId); @@ -127,8 +129,6 @@ public final class UserVisibilityMediatorMUPANDTest listener.verify(); } - /* TODO(b/261538337): re-add after the reverted CL is merged again - @Test public void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBgOnSecondaryDisplay() @@ -226,5 +226,4 @@ public final class UserVisibilityMediatorMUPANDTest listener.verify(); } - */ } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java index 1bf921c503d8..277480316c66 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java @@ -44,7 +44,6 @@ import android.text.TextUtils; import android.util.IntArray; import android.util.Log; -import com.android.internal.util.Preconditions; import com.android.server.DumpableDumperRule; import com.android.server.ExpectableTestCase; @@ -152,6 +151,12 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { } @Test + public final void testAssignUserToDisplayOnStart_invalidUserStartMode() { + assertThrows(IllegalArgumentException.class, () -> mMediator + .assignUserToDisplayOnStart(USER_ID, USER_ID, 666, DEFAULT_DISPLAY)); + } + + @Test public final void testStartFgUser_onSecondaryDisplay() throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); @@ -286,7 +291,7 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG_VISIBLE, DEFAULT_DISPLAY); - assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); expectNoDisplayAssignedToUser(PROFILE_USER_ID); @@ -302,14 +307,14 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG_VISIBLE, DEFAULT_DISPLAY); - assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); expectNoDisplayAssignedToUser(PROFILE_USER_ID); expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY); - assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); listener.verify(); } @@ -335,6 +340,41 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { } @Test + public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForNoEvents(); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, + DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + + listener.verify(); + } + + @Test + public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForNoEvents(); + startBackgroundUser(PARENT_USER_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, + DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY); + + assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + @Test public final void testStartBgProfile_onSecondaryDisplay() throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); @@ -488,8 +528,6 @@ abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { * se. */ protected final void startUserInSecondaryDisplay(@UserIdInt int userId, int displayId) { - Preconditions.checkArgument(displayId != INVALID_DISPLAY && displayId != DEFAULT_DISPLAY, - "must pass a secondary display, not %d", displayId); Log.d(TAG, "startUserInSecondaryDisplay(" + userId + ", " + displayId + ")"); int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG_VISIBLE, displayId); if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java index af85ef4b6b87..e82910f25a2c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java @@ -109,34 +109,6 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase } @Test - public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser() - throws Exception { - AsyncUserVisibilityListener listener = addListenerForEvents( - onInvisible(INITIAL_CURRENT_USER_ID), - onVisible(PARENT_USER_ID), - onVisible(PROFILE_USER_ID)); - startForegroundUser(PARENT_USER_ID); - - int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, - BG_VISIBLE, DEFAULT_DISPLAY); - assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); - expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); - - expectUserIsVisible(PROFILE_USER_ID); - expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY); - expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); - expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); - expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID); - - expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY); - expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID); - - assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); - - listener.verify(); - } - - @Test public final void testStartFgUser_onInvalidDisplay() throws Exception { AsyncUserVisibilityListener listener = addListenerForNoEvents(); @@ -301,14 +273,83 @@ abstract class UserVisibilityMediatorVisibleBackgroundUserTestCase } @Test + public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForEvents( + onInvisible(INITIAL_CURRENT_USER_ID), + onVisible(PARENT_USER_ID), + onVisible(PROFILE_USER_ID)); + startForegroundUser(PARENT_USER_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE); + expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); + + expectUserIsVisible(PROFILE_USER_ID); + expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY); + expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY); + expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID); + + expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY); + expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID); + + assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + @Test public final void - testStartVisibleBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay() - throws Exception { + testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnAnotherDisplay() + throws Exception { AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID)); startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID); + + assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + // Not supported - profiles can only be started on default display + @Test + public final void + testStartVisibleBgProfile_onSecondaryDisplay_whenParentIsStartedVisibleOnThatDisplay() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID)); + startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, + BG_VISIBLE, DEFAULT_DISPLAY); + assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE); + + expectUserIsNotVisibleAtAll(PROFILE_USER_ID); + expectNoDisplayAssignedToUser(PROFILE_USER_ID); + expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID); + + assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID); + + listener.verify(); + } + + @Test + public final void + testStartProfile_onDefaultDisplay_whenParentIsStartedVisibleOnSecondaryDisplay() + throws Exception { + AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID)); + startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID); + + int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG, + DEFAULT_DISPLAY); assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE); expectUserIsNotVisibleAtAll(PROFILE_USER_ID); diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 3a7b9a49f161..6f26a5fe8970 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -31,6 +31,7 @@ android_test { "services.backup", "services.companion", "services.core", + "services.credentials", "services.devicepolicy", "services.net", "services.people", @@ -115,6 +116,7 @@ android_test { ":StubTestApp", ":SuspendTestApp", ":MediaButtonReceiverHolderTestHelperApp", + "data/broken_shortcut.xml", ], java_resources: [ diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml index d9676470aca3..b304968f3e69 100644 --- a/services/tests/servicestests/AndroidTest.xml +++ b/services/tests/servicestests/AndroidTest.xml @@ -21,6 +21,8 @@ <option name="cleanup" value="true" /> <option name="push-file" key="SimpleServiceTestApp3.apk" value="/data/local/tmp/cts/content/SimpleServiceTestApp3.apk" /> + <option name="push-file" key="broken_shortcut.xml" + value="/data/local/tmp/cts/content/broken_shortcut.xml" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> diff --git a/services/tests/servicestests/data/broken_shortcut.xml b/services/tests/servicestests/data/broken_shortcut.xml Binary files differnew file mode 100644 index 000000000000..f2b083ddc3a0 --- /dev/null +++ b/services/tests/servicestests/data/broken_shortcut.xml diff --git a/services/tests/servicestests/res/xml/irq_device_map_3.xml b/services/tests/servicestests/res/xml/irq_device_map_3.xml index 498b676dd1dc..1d2a7d37d613 100644 --- a/services/tests/servicestests/res/xml/irq_device_map_3.xml +++ b/services/tests/servicestests/res/xml/irq_device_map_3.xml @@ -21,6 +21,6 @@ <subsystem>Alarm</subsystem> </device> <device name="test.wifi.device"> - <subsystem>undefined</subsystem> + <subsystem>Wifi</subsystem> </device> </irq-device-map>
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 93dfee6f2da4..8c7b0c5a569a 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -528,7 +528,7 @@ public class ActivityManagerServiceTest { ActivityManager.PROCESS_CAPABILITY_NONE, ActivityManager.PROCESS_CAPABILITY_NONE, ActivityManager.PROCESS_CAPABILITY_NONE, - ActivityManager.PROCESS_CAPABILITY_NETWORK, + ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK, }; final Map<Integer, ChangeRecord> changeItems = new HashMap<>(); for (int i = 0; i < changesForPendingUidRecords.length; ++i) { diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java index 8a3f246fd656..f788c92b24b2 100644 --- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java @@ -18,8 +18,8 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; -import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; +import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT; import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; @@ -185,10 +185,10 @@ public class UidObserverControllerTest { verifyNoMoreInteractions(observer2); addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY, - PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_NETWORK, false); + PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK, false); mUidObserverController.dispatchUidsChanged(); verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER, - 111, PROCESS_CAPABILITY_NETWORK); + 111, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); verifyNoMoreInteractions(observer1); verifyNoMoreInteractions(observer2); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java index 3ff802c0125c..6b0e33037af8 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.face.aidl; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -30,11 +32,15 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.content.ComponentName; +import android.hardware.biometrics.common.AuthenticateReason; import android.hardware.biometrics.common.ICancellationSignal; +import android.hardware.biometrics.common.OperationContext; +import android.hardware.biometrics.common.WakeReason; import android.hardware.biometrics.face.ISession; import android.hardware.face.Face; import android.hardware.face.FaceAuthenticateOptions; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.testing.TestableContext; @@ -69,6 +75,8 @@ public class FaceAuthenticationClientTest { private static final int USER_ID = 12; private static final long OP_ID = 32; + private static final int WAKE_REASON = WakeReason.LIFT; + private static final int AUTH_REASON = AuthenticateReason.Face.ASSISTANT_VISIBLE; @Rule public final TestableContext mContext = new TestableContext( @@ -126,8 +134,13 @@ public class FaceAuthenticationClientTest { InOrder order = inOrder(mHal, mBiometricContext); order.verify(mBiometricContext).updateContext( mOperationContextCaptor.capture(), anyBoolean()); - order.verify(mHal).authenticateWithContext( - eq(OP_ID), same(mOperationContextCaptor.getValue().toAidlContext())); + + final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext(); + order.verify(mHal).authenticateWithContext(eq(OP_ID), same(aidlContext)); + assertThat(aidlContext.wakeReason).isEqualTo(WAKE_REASON); + assertThat(aidlContext.authenticateReason.getFaceAuthenticateReason()) + .isEqualTo(AUTH_REASON); + verify(mHal, never()).authenticate(anyLong()); } @@ -156,8 +169,11 @@ public class FaceAuthenticationClientTest { final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback); final FaceAuthenticateOptions options = new FaceAuthenticateOptions.Builder() .setOpPackageName("test-owner") - .setUserId(5) + .setUserId(USER_ID) .setSensorId(9) + .setWakeReason(PowerManager.WAKE_REASON_LIFT) + .setAuthenticateReason( + FaceAuthenticateOptions.AUTHENTICATE_REASON_ASSISTANT_VISIBLE) .build(); return new FaceAuthenticationClient(mContext, () -> aidl, mToken, 2 /* requestId */, mClientMonitorCallbackConverter, OP_ID, diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java index c4c550549f73..0abfa7e6546d 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.face.aidl; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.inOrder; @@ -24,9 +26,13 @@ import static org.mockito.Mockito.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.hardware.biometrics.common.AuthenticateReason; +import android.hardware.biometrics.common.OperationContext; +import android.hardware.biometrics.common.WakeReason; import android.hardware.biometrics.face.ISession; import android.hardware.face.FaceAuthenticateOptions; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.testing.TestableContext; @@ -55,6 +61,8 @@ import org.mockito.junit.MockitoRule; public class FaceDetectClientTest { private static final int USER_ID = 12; + private static final int WAKE_REASON = WakeReason.POWER_BUTTON; + private static final int AUTH_REASON = AuthenticateReason.Face.OCCLUDING_APP_REQUESTED; @Rule public final TestableContext mContext = new TestableContext( @@ -103,8 +111,13 @@ public class FaceDetectClientTest { InOrder order = inOrder(mHal, mBiometricContext); order.verify(mBiometricContext).updateContext( mOperationContextCaptor.capture(), anyBoolean()); - order.verify(mHal).detectInteractionWithContext( - same(mOperationContextCaptor.getValue().toAidlContext())); + + final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext(); + order.verify(mHal).detectInteractionWithContext(same(aidlContext)); + assertThat(aidlContext.wakeReason).isEqualTo(WAKE_REASON); + assertThat(aidlContext.authenticateReason.getFaceAuthenticateReason()) + .isEqualTo(AUTH_REASON); + verify(mHal, never()).detectInteraction(); } @@ -118,6 +131,9 @@ public class FaceDetectClientTest { .setUserId(USER_ID) .setSensorId(5) .setOpPackageName("own-it") + .setWakeReason(PowerManager.WAKE_REASON_POWER_BUTTON) + .setAuthenticateReason( + FaceAuthenticateOptions.AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED) .build(), mBiometricLogger, mBiometricContext, false /* isStrongBiometric */, null /* sensorPrivacyManager */); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index f0f975ccf5ff..c6645003c7e2 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -36,6 +36,7 @@ import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.content.ComponentName; import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.common.AuthenticateReason; import android.hardware.biometrics.common.ICancellationSignal; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.fingerprint.ISession; @@ -165,8 +166,12 @@ public class FingerprintAuthenticationClientTest { InOrder order = inOrder(mHal, mBiometricContext); order.verify(mBiometricContext).updateContext( mOperationContextCaptor.capture(), anyBoolean()); - order.verify(mHal).authenticateWithContext( - eq(OP_ID), same(mOperationContextCaptor.getValue().toAidlContext())); + + final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext(); + order.verify(mHal).authenticateWithContext(eq(OP_ID), same(aidlContext)); + assertThat(aidlContext.authenticateReason.getFingerprintAuthenticateReason()) + .isEqualTo(AuthenticateReason.Fingerprint.UNKNOWN); + verify(mHal, never()).authenticate(anyLong()); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java index e741e446da85..c20cc392f5c0 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.any; import static org.mockito.Mockito.inOrder; @@ -24,6 +26,8 @@ import static org.mockito.Mockito.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.hardware.biometrics.common.AuthenticateReason; +import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.fingerprint.ISession; import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.IUdfpsOverlayController; @@ -108,8 +112,12 @@ public class FingerprintDetectClientTest { InOrder order = inOrder(mHal, mBiometricContext); order.verify(mBiometricContext).updateContext( mOperationContextCaptor.capture(), anyBoolean()); - order.verify(mHal).detectInteractionWithContext( - same(mOperationContextCaptor.getValue().toAidlContext())); + + final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext(); + order.verify(mHal).detectInteractionWithContext(same(aidlContext)); + assertThat(aidlContext.authenticateReason.getFingerprintAuthenticateReason()) + .isEqualTo(AuthenticateReason.Fingerprint.UNKNOWN); + verify(mHal, never()).detectInteraction(); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java index 26524d7df7c3..7646c401193f 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java @@ -273,16 +273,6 @@ public class FingerprintEnrollClientTest { showHideOverlay(c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0)); } - @Test - public void testPowerPressForwardsAcquireMessage() throws RemoteException { - final FingerprintEnrollClient client = createClient(); - client.start(mCallback); - client.onPowerPressed(); - - verify(mClientMonitorCallbackConverter).onAcquired(anyInt(), - eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt()); - } - private void showHideOverlay(Consumer<FingerprintEnrollClient> block) throws RemoteException { final FingerprintEnrollClient client = createClient(); diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 09a84da9406a..339ccd80c351 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -18,6 +18,7 @@ package com.android.server.companion.virtual; import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM; import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; +import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS; import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.content.Context.DEVICE_ID_INVALID; @@ -117,6 +118,7 @@ import com.android.server.sensors.SensorManagerInternal; import com.google.android.collect.Sets; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -128,7 +130,6 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Set; import java.util.function.Consumer; @@ -281,7 +282,7 @@ public class VirtualDeviceManagerServiceTest { return blockedActivities; } - private Intent createRestrictedActivityBlockedIntent(List displayCategories, + private Intent createRestrictedActivityBlockedIntent(Set<String> displayCategories, String targetDisplayCategory) { when(mDisplayManagerInternalMock.createVirtualDisplay(any(), any(), any(), any(), eq(NONBLOCKED_APP_PACKAGE_NAME))).thenReturn(DISPLAY_ID_1); @@ -372,6 +373,11 @@ public class VirtualDeviceManagerServiceTest { mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1); } + @After + public void tearDown() { + mDeviceImpl.close(); + } + @Test public void getDeviceIdForDisplayId_invalidDisplayId_returnsDefault() { assertThat(mVdm.getDeviceIdForDisplayId(Display.INVALID_DISPLAY)) @@ -444,6 +450,7 @@ public class VirtualDeviceManagerServiceTest { .setBlockedActivities(getBlockedActivities()) .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM) .build(); + mDeviceImpl.close(); mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params); assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS)) @@ -451,6 +458,35 @@ public class VirtualDeviceManagerServiceTest { } @Test + public void getDevicePolicy_defaultRecentsPolicy_gwpcCanShowRecentsOnHostDevice() { + VirtualDeviceParams params = new VirtualDeviceParams + .Builder() + .build(); + mDeviceImpl.close(); + mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + + GenericWindowPolicyController gwpc = + mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1); + assertThat(gwpc.canShowTasksInHostDeviceRecents()).isTrue(); + } + + @Test + public void getDevicePolicy_customRecentsPolicy_gwpcCannotShowRecentsOnHostDevice() { + VirtualDeviceParams params = new VirtualDeviceParams + .Builder() + .setDevicePolicy(POLICY_TYPE_RECENTS, DEVICE_POLICY_CUSTOM) + .build(); + mDeviceImpl.close(); + mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params); + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + + GenericWindowPolicyController gwpc = + mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1); + assertThat(gwpc.canShowTasksInHostDeviceRecents()).isFalse(); + } + + @Test public void getDeviceOwnerUid_oneDevice_returnsCorrectId() { int ownerUid = mLocalService.getDeviceOwnerUid(mDeviceImpl.getDeviceId()); assertThat(ownerUid).isEqualTo(mDeviceImpl.getOwnerUid()); @@ -501,6 +537,7 @@ public class VirtualDeviceManagerServiceTest { doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor( anyInt(), anyInt(), anyString(), anyString(), anyInt(), any()); + mDeviceImpl.close(); mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params); VirtualSensor sensor = mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE); @@ -1596,7 +1633,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void nonRestrictedActivityOnRestrictedVirtualDisplay_startBlockedAlertActivity() { - Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), + Intent blockedAppIntent = createRestrictedActivityBlockedIntent(Set.of("abc"), /* targetDisplayCategory= */ null); verify(mContext).startActivityAsUser(argThat(intent -> intent.filterEquals(blockedAppIntent)), any(), any()); @@ -1604,7 +1641,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void restrictedActivityOnRestrictedVirtualDisplay_doesNotStartBlockedAlertActivity() { - Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "abc"); + Intent blockedAppIntent = createRestrictedActivityBlockedIntent(Set.of("abc"), "abc"); verify(mContext, never()).startActivityAsUser(argThat(intent -> intent.filterEquals(blockedAppIntent)), any(), any()); } @@ -1612,14 +1649,14 @@ public class VirtualDeviceManagerServiceTest { @Test public void restrictedActivityOnNonRestrictedVirtualDisplay_startBlockedAlertActivity() { Intent blockedAppIntent = createRestrictedActivityBlockedIntent( - /* displayCategories= */ List.of(), "abc"); + /* displayCategories= */ Set.of(), "abc"); verify(mContext).startActivityAsUser(argThat(intent -> intent.filterEquals(blockedAppIntent)), any(), any()); } @Test public void restrictedActivityNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() { - Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "def"); + Intent blockedAppIntent = createRestrictedActivityBlockedIntent(Set.of("abc"), "def"); verify(mContext).startActivityAsUser(argThat(intent -> intent.filterEquals(blockedAppIntent)), any(), any()); } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java index 7b5af1e0fe98..2bfa44ecb1d6 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java @@ -89,9 +89,8 @@ public class VirtualAudioControllerTest { /* activityBlockedCallback= */ null, /* secureWindowCallback= */ null, /* intentListenerCallback= */ null, - /* displayCategories= */ new ArrayList<>(), - /* recentsPolicy= */ - VirtualDeviceParams.RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS); + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true); } diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java new file mode 100644 index 000000000000..b7085f152fa0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java @@ -0,0 +1,197 @@ +/* + * 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.credentials; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.credentials.CredentialDescription; +import android.credentials.RegisterCredentialDescriptionRequest; +import android.service.credentials.CredentialEntry; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Tests for CredentialDescriptionRegistry. + * + * atest FrameworksServicesTests:com.android.server.credentials.CredentialDescriptionRegistryTest + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class CredentialDescriptionRegistryTest { + + private static final int USER_ID_1 = 1; + private static final int USER_ID_2 = 2; + private static final String CALLING_PACKAGE_NAME = "com.credman.app"; + private static final String CALLING_PACKAGE_NAME_2 = "com.credman.app2"; + private static final String MDOC_CREDENTIAL_TYPE = "MDOC"; + private static final String PASSKEY_CREDENTIAL_TYPE = "PASSKEY"; + private static final String FLATTENED_REQUEST = "FLATTENED_REQ"; + private static final String FLATTENED_REQUEST_2 = "FLATTENED_REQ_2"; + + private CredentialDescriptionRegistry mCredentialDescriptionRegistry; + private CredentialEntry mEntry; + private CredentialEntry mEntry2; + private CredentialEntry mEntry3; + + @SuppressWarnings("GuardedBy") + @Before + public void setUp() { + CredentialDescriptionRegistry.clearAllSessions(); + mEntry = mock(CredentialEntry.class); + mEntry2 = mock(CredentialEntry.class); + mEntry3 = mock(CredentialEntry.class); + when(mEntry.getType()).thenReturn(MDOC_CREDENTIAL_TYPE); + when(mEntry2.getType()).thenReturn(MDOC_CREDENTIAL_TYPE); + when(mEntry3.getType()).thenReturn(PASSKEY_CREDENTIAL_TYPE); + mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(USER_ID_1); + } + + @SuppressWarnings("GuardedBy") + @Test + public void testForUser_createsUniqueInstanceForEachUserID() { + final CredentialDescriptionRegistry secondRegistry = CredentialDescriptionRegistry + .forUser(USER_ID_2); + + assertThat(mCredentialDescriptionRegistry).isNotSameInstanceAs(secondRegistry); + } + + @SuppressWarnings("GuardedBy") + @Test + public void testForUser_returnsSameInstanceForSameUserID() { + final CredentialDescriptionRegistry secondRegistry = CredentialDescriptionRegistry + .forUser(USER_ID_1); + + assertThat(mCredentialDescriptionRegistry).isSameInstanceAs(secondRegistry); + } + + @SuppressWarnings("GuardedBy") + @Test + public void testClearUserSession_removesExistingSessionForUserID() { + CredentialDescriptionRegistry.clearUserSession(USER_ID_1); + final CredentialDescriptionRegistry secondRegistry = CredentialDescriptionRegistry + .forUser(USER_ID_1); + + assertThat(mCredentialDescriptionRegistry).isNotSameInstanceAs(secondRegistry); + } + + @Test + public void testEvictProvider_existingProviders_succeeds() { + final CredentialDescription credentialDescription = + new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST, + Collections.emptyList()); + final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest = + new RegisterCredentialDescriptionRequest(credentialDescription); + final CredentialDescription credentialDescription2 = + new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST_2, + Collections.emptyList()); + final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest2 = + new RegisterCredentialDescriptionRequest(credentialDescription2); + + + mCredentialDescriptionRegistry + .executeRegisterRequest(registerCredentialDescriptionRequest, CALLING_PACKAGE_NAME); + mCredentialDescriptionRegistry + .executeRegisterRequest(registerCredentialDescriptionRequest2, + CALLING_PACKAGE_NAME); + mCredentialDescriptionRegistry.evictProviderWithPackageName(CALLING_PACKAGE_NAME); + Set<CredentialDescriptionRegistry.FilterResult> providers = mCredentialDescriptionRegistry + .getMatchingProviders(Set.of(FLATTENED_REQUEST)); + + assertThat(providers).isEmpty(); + } + + @Test + public void testGetMatchingProviders_existingProviders_succeeds() { + final CredentialDescription credentialDescription = + new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST, + Collections.emptyList()); + final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest = + new RegisterCredentialDescriptionRequest(credentialDescription); + final CredentialDescription credentialDescription2 = + new CredentialDescription(MDOC_CREDENTIAL_TYPE, FLATTENED_REQUEST, + Collections.emptyList()); + final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest2 = + new RegisterCredentialDescriptionRequest(credentialDescription2); + + + mCredentialDescriptionRegistry + .executeRegisterRequest(registerCredentialDescriptionRequest, + CALLING_PACKAGE_NAME); + mCredentialDescriptionRegistry + .executeRegisterRequest(registerCredentialDescriptionRequest2, + CALLING_PACKAGE_NAME_2); + + Set<CredentialDescriptionRegistry.FilterResult> providers = mCredentialDescriptionRegistry + .getMatchingProviders(Set.of(FLATTENED_REQUEST)); + Set<String> packageNames = providers.stream().map( + filterResult -> filterResult.mPackageName).collect(Collectors.toSet()); + + assertThat(providers).hasSize(2); + assertThat(packageNames).contains(CALLING_PACKAGE_NAME); + assertThat(packageNames).contains(CALLING_PACKAGE_NAME_2); + } + + @Test + public void testExecuteRegisterRequest_noProviders_filterSucceedsWithNoResults() { + List<CredentialDescriptionRegistry.FilterResult> results = mCredentialDescriptionRegistry + .getFilteredResultForProvider(CALLING_PACKAGE_NAME, + FLATTENED_REQUEST).stream().toList(); + + assertThat(results).isEmpty(); + } + + @Test + public void testExecuteRegisterRequest_existingProviders_filterSucceeds() { + final CredentialDescription credentialDescription = + new CredentialDescription(MDOC_CREDENTIAL_TYPE, + FLATTENED_REQUEST, + List.of(mEntry, mEntry2)); + final CredentialDescription credentialDescription2 = + new CredentialDescription(PASSKEY_CREDENTIAL_TYPE, + FLATTENED_REQUEST_2, + List.of(mEntry3)); + final RegisterCredentialDescriptionRequest registerCredentialDescriptionRequest = + new RegisterCredentialDescriptionRequest(Set.of(credentialDescription, + credentialDescription2)); + + mCredentialDescriptionRegistry + .executeRegisterRequest(registerCredentialDescriptionRequest, CALLING_PACKAGE_NAME); + + List<CredentialDescriptionRegistry.FilterResult> results = mCredentialDescriptionRegistry + .getFilteredResultForProvider(CALLING_PACKAGE_NAME, FLATTENED_REQUEST) + .stream().toList(); + + assertThat(results).hasSize(1); + assertThat(results.get(0).mCredentialEntries).hasSize(2); + assertThat(results.get(0).mCredentialEntries.get(0)).isSameInstanceAs(mEntry); + assertThat(results.get(0).mCredentialEntries.get(1)).isSameInstanceAs(mEntry2); + } + +} diff --git a/services/tests/servicestests/src/com/android/server/credentials/OWNERS b/services/tests/servicestests/src/com/android/server/credentials/OWNERS new file mode 100644 index 000000000000..cc73854c665e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/credentials/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/base:/core/java/android/credentials/OWNERS
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 1f25da7a3cef..aaabb286589c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -162,9 +162,9 @@ import com.android.server.pm.UserRestrictionsUtils; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; -import org.junit.Ignore; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; import org.mockito.internal.util.collections.Sets; @@ -514,7 +514,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(CALLER_USER_HANDLE)); + MockUtils.checkUserHandle(CALLER_USER_HANDLE), + eq(null), + any(Bundle.class)); verify(mContext.spiedContext).sendBroadcastAsUser( MockUtils.checkIntentAction( DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), @@ -793,7 +795,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(CALLER_USER_HANDLE)); + MockUtils.checkUserHandle(CALLER_USER_HANDLE), + eq(null), + any(Bundle.class)); // Remove. No permissions, but same user, so it'll work. mContext.callerPermissions.clear(); @@ -820,7 +824,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(CALLER_USER_HANDLE)); + MockUtils.checkUserHandle(CALLER_USER_HANDLE), + eq(null), + any(Bundle.class)); // TODO Check other internal calls. } @@ -846,7 +852,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(CALLER_USER_HANDLE)); + MockUtils.checkUserHandle(CALLER_USER_HANDLE), + eq(null), + any(Bundle.class)); // Remove. No permissions, but same user, so it'll work. mContext.callerPermissions.clear(); @@ -874,7 +882,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext, times(3)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(CALLER_USER_HANDLE)); + MockUtils.checkUserHandle(CALLER_USER_HANDLE), + eq(null), + any(Bundle.class)); } /** @@ -2425,7 +2435,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(CALLER_USER_HANDLE)); + MockUtils.checkUserHandle(CALLER_USER_HANDLE), + eq(null), + any(Bundle.class)); verify(mContext.spiedContext).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED), @@ -5886,7 +5898,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), - MockUtils.checkUserHandle(userHandle)); + MockUtils.checkUserHandle(userHandle), + eq(null), + any(Bundle.class)); final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED); intent.setComponent(admin1); diff --git a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java index a380efffb62f..e74b278bd904 100644 --- a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java @@ -157,6 +157,26 @@ public class DeviceStateToLayoutMapTest { assertEquals(testLayout, configLayout); } + @Test + public void testRefreshRateThermalThrottlingMapId() { + Layout configLayout = mDeviceStateToLayoutMap.get(4); + + Layout testLayout = new Layout(); + Layout.Display display1 = testLayout.createDisplayLocked( + DisplayAddress.fromPhysicalDisplayId(345L), /* isDefault= */ true, + /* isEnabled= */ true, /* displayGroup= */ null, mDisplayIdProducerMock, + /* brightnessThrottlingMapId= */ null, + /* leadDisplayId= */ Display.DEFAULT_DISPLAY); + display1.setRefreshRateThermalThrottlingMapId("test2"); + testLayout.createDisplayLocked( + DisplayAddress.fromPhysicalDisplayId(678L), /* isDefault= */ false, + /* isEnabled= */ true, /* displayGroup= */ null, mDisplayIdProducerMock, + /* brightnessThrottlingMapId= */ null, + /* leadDisplayId= */ Display.DEFAULT_DISPLAY); + + assertEquals(testLayout, configLayout); + } + //////////////////// // Helper Methods // //////////////////// @@ -221,6 +241,19 @@ public class DeviceStateToLayoutMapTest { + "<address>678</address>\n" + "</display>\n" + "</layout>\n" + + + "<layout>\n" + + "<state>4</state> \n" + + "<display enabled=\"true\" defaultDisplay=\"true\" >\n" + + "<address>345</address>\n" + + "<refreshRateThermalThrottlingMapId>" + + "test2" + + "</refreshRateThermalThrottlingMapId>" + + "</display>\n" + + "<display enabled=\"true\">\n" + + "<address>678</address>\n" + + "</display>\n" + + "</layout>\n" + "</layouts>\n"; } } diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java index fdfcd81cbef9..45f103718602 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -20,6 +20,7 @@ package com.android.server.display; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; @@ -28,6 +29,9 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; +import android.os.Temperature; +import android.util.SparseArray; +import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -82,6 +86,7 @@ public final class DisplayDeviceConfigTest { public void testConfigValuesFromDisplayConfig() throws IOException { setupDisplayDeviceConfigFromDisplayConfigFile(); + assertEquals(mDisplayDeviceConfig.getName(), "Example Display"); assertEquals(mDisplayDeviceConfig.getAmbientHorizonLong(), 5000); assertEquals(mDisplayDeviceConfig.getAmbientHorizonShort(), 50); assertEquals(mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(), 3000); @@ -237,6 +242,7 @@ public final class DisplayDeviceConfigTest { @Test public void testConfigValuesFromConfigResource() { setupDisplayDeviceConfigFromConfigResourceFile(); + assertNull(mDisplayDeviceConfig.getName()); assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new float[]{2.0f, 200.0f, 600.0f}, ZERO_DELTA); assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new @@ -315,9 +321,59 @@ public final class DisplayDeviceConfigTest { // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor. } + @Test + public void testRefreshRateThermalThrottlingFromDisplayConfig() throws IOException { + setupDisplayDeviceConfigFromDisplayConfigFile(); + + SparseArray<SurfaceControl.RefreshRateRange> defaultMap = + mDisplayDeviceConfig.getRefreshRateThrottlingData(null); + assertNotNull(defaultMap); + assertEquals(2, defaultMap.size()); + assertEquals(30, defaultMap.get(Temperature.THROTTLING_CRITICAL).min, SMALL_DELTA); + assertEquals(60, defaultMap.get(Temperature.THROTTLING_CRITICAL).max, SMALL_DELTA); + assertEquals(0, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).min, SMALL_DELTA); + assertEquals(30, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).max, SMALL_DELTA); + + SparseArray<SurfaceControl.RefreshRateRange> testMap = + mDisplayDeviceConfig.getRefreshRateThrottlingData("test"); + assertNotNull(testMap); + assertEquals(1, testMap.size()); + assertEquals(60, testMap.get(Temperature.THROTTLING_EMERGENCY).min, SMALL_DELTA); + assertEquals(90, testMap.get(Temperature.THROTTLING_EMERGENCY).max, SMALL_DELTA); + } + + private String getRefreshThermalThrottlingMaps() { + return "<refreshRateThrottlingMap>\n" + + " <refreshRateThrottlingPoint>\n" + + " <thermalStatus>critical</thermalStatus>\n" + + " <refreshRateRange>\n" + + " <minimum>30</minimum>\n" + + " <maximum>60</maximum>\n" + + " </refreshRateRange>\n" + + " </refreshRateThrottlingPoint>\n" + + " <refreshRateThrottlingPoint>\n" + + " <thermalStatus>shutdown</thermalStatus>\n" + + " <refreshRateRange>\n" + + " <minimum>0</minimum>\n" + + " <maximum>30</maximum>\n" + + " </refreshRateRange>\n" + + " </refreshRateThrottlingPoint>\n" + + "</refreshRateThrottlingMap>\n" + + "<refreshRateThrottlingMap id=\"test\">\n" + + " <refreshRateThrottlingPoint>\n" + + " <thermalStatus>emergency</thermalStatus>\n" + + " <refreshRateRange>\n" + + " <minimum>60</minimum>\n" + + " <maximum>90</maximum>\n" + + " </refreshRateRange>\n" + + " </refreshRateThrottlingPoint>\n" + + "</refreshRateThrottlingMap>\n"; + } + private String getContent() { return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<displayConfiguration>\n" + + "<name>Example Display</name>" + "<screenBrightnessMap>\n" + "<point>\n" + "<value>0.0</value>\n" @@ -557,6 +613,7 @@ public final class DisplayDeviceConfigTest { + "<brightness>0.0125</brightness>\n" + "</brightnessThrottlingPoint>\n" + "</brightnessThrottlingMap>\n" + + getRefreshThermalThrottlingMaps() + "</thermalThrottling>\n" + "<refreshRate>\n" + "<defaultRefreshRate>45</defaultRefreshRate>\n" diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index 7971fd71ea09..de1c2195fcdb 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -967,7 +967,7 @@ public class DisplayManagerServiceTest { final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder( VIRTUAL_DISPLAY_NAME, width, height, dpi) .setUniqueId(uniqueId2) - .setWindowManagerMirroring(true); + .setWindowManagerMirroringEnabled(true); final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(), mMockAppToken2 /* callback */, null /* projection */, PACKAGE_NAME); diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index b698cdf10816..9eb600304f98 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -687,10 +687,10 @@ public class LogicalDisplayMapperTest { assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked()); - assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID, + assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device1) .getBrightnessThrottlingDataIdLocked()); - assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID, + assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device2) .getBrightnessThrottlingDataIdLocked()); @@ -700,10 +700,10 @@ public class LogicalDisplayMapperTest { assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked()); - assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID, + assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device1) .getBrightnessThrottlingDataIdLocked()); - assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID, + assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device2) .getBrightnessThrottlingDataIdLocked()); } diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java index bbed1b60f8bf..618ab1b75587 100644 --- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java @@ -34,6 +34,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Resources; import android.hardware.display.ColorDisplayManager; +import android.hardware.display.DisplayManagerInternal; import android.hardware.display.Time; import android.os.Handler; import android.os.UserHandle; @@ -77,6 +78,7 @@ public class ColorDisplayServiceTest { private MockTwilightManager mTwilightManager; private DisplayTransformManager mDisplayTransformManager; + private DisplayManagerInternal mDisplayManagerInternal; private ColorDisplayService mCds; private ColorDisplayService.BinderService mBinderService; @@ -116,6 +118,10 @@ public class ColorDisplayServiceTest { doReturn(true).when(mDisplayTransformManager).needsLinearColorMatrix(); LocalServices.addService(DisplayTransformManager.class, mDisplayTransformManager); + mDisplayManagerInternal = Mockito.mock(DisplayManagerInternal.class); + LocalServices.removeServiceForTest(DisplayManagerInternal.class); + LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternal); + mCds = new ColorDisplayService(mContext); mBinderService = mCds.new BinderService(); LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class, @@ -142,6 +148,7 @@ public class ColorDisplayServiceTest { FakeSettingsProvider.clearSettingsProvider(); LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); + LocalServices.removeServiceForTest(DisplayManagerInternal.class); } @Test diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index f256c8a17c56..1b02799e1da4 100644 --- a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -59,12 +59,12 @@ import android.hardware.SensorManager; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; +import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; import android.os.Handler; import android.os.IThermalEventListener; -import android.os.IThermalService; import android.os.Looper; import android.os.RemoteException; import android.os.Temperature; @@ -75,6 +75,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.Display; +import android.view.DisplayInfo; import android.view.SurfaceControl.RefreshRateRange; import android.view.SurfaceControl.RefreshRateRanges; @@ -83,6 +84,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.internal.display.BrightnessSynchronizer; +import com.android.internal.os.BackgroundThread; import com.android.internal.util.Preconditions; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProviderRule; @@ -140,8 +142,6 @@ public class DisplayModeDirectorTest { public SensorManagerInternal mSensorManagerInternalMock; @Mock public DisplayManagerInternal mDisplayManagerInternalMock; - @Mock - public IThermalService mThermalServiceMock; @Before public void setUp() throws Exception { @@ -150,7 +150,6 @@ public class DisplayModeDirectorTest { final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); when(mContext.getContentResolver()).thenReturn(resolver); mInjector = spy(new FakesInjector()); - when(mInjector.getThermalService()).thenReturn(mThermalServiceMock); mHandler = new Handler(Looper.getMainLooper()); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); @@ -1773,11 +1772,12 @@ public class DisplayModeDirectorTest { ArgumentCaptor<DisplayListener> DisplayCaptor = ArgumentCaptor.forClass(DisplayListener.class); - verify(mInjector).registerDisplayListener(DisplayCaptor.capture(), any(Handler.class), + verify(mInjector, times(2)).registerDisplayListener(DisplayCaptor.capture(), + any(Handler.class), eq(DisplayManager.EVENT_FLAG_DISPLAY_ADDED | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); - DisplayListener displayListener = DisplayCaptor.getValue(); + DisplayListener displayListener = DisplayCaptor.getAllValues().get(0); // Verify that there is no proximity vote initially Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY); @@ -2236,8 +2236,7 @@ public class DisplayModeDirectorTest { ArgumentCaptor<IThermalEventListener> thermalEventListener = ArgumentCaptor.forClass(IThermalEventListener.class); - verify(mThermalServiceMock).registerThermalEventListenerWithType( - thermalEventListener.capture(), eq(Temperature.TYPE_SKIN)); + verify(mInjector).registerThermalServiceListener(thermalEventListener.capture()); final IThermalEventListener listener = thermalEventListener.getValue(); // Verify that there is no skin temperature vote initially. @@ -2246,11 +2245,13 @@ public class DisplayModeDirectorTest { // Set the skin temperature to critical and verify that we added a vote. listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL)); + BackgroundThread.getHandler().runWithScissors(() -> { }, 500 /*timeout*/); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); assertVoteForRenderFrameRateRange(vote, 0f, 60.f); // Set the skin temperature to severe and verify that the vote is gone. listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE)); + BackgroundThread.getHandler().runWithScissors(() -> { }, 500 /*timeout*/); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); assertNull(vote); } @@ -2709,6 +2710,16 @@ public class DisplayModeDirectorTest { public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {} @Override + public Display[] getDisplays() { + return new Display[] { createDisplay(DISPLAY_ID) }; + } + + @Override + public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { + return false; + } + + @Override public BrightnessInfo getBrightnessInfo(int displayId) { return null; } @@ -2719,8 +2730,8 @@ public class DisplayModeDirectorTest { } @Override - public IThermalService getThermalService() { - return null; + public boolean registerThermalServiceListener(IThermalEventListener listener) { + return true; } @Override @@ -2728,6 +2739,11 @@ public class DisplayModeDirectorTest { return true; } + protected Display createDisplay(int id) { + return new Display(DisplayManagerGlobal.getInstance(), id, new DisplayInfo(), + ApplicationProvider.getApplicationContext().getResources()); + } + void notifyPeakRefreshRateChanged() { if (mPeakRefreshRateObserver != null) { mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/, diff --git a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java new file mode 100644 index 000000000000..dd0cd965b8a0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java @@ -0,0 +1,247 @@ +/* + * 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.display.mode; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.hardware.display.DisplayManager; +import android.os.Handler; +import android.os.IThermalEventListener; +import android.os.Temperature; +import android.util.SparseArray; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.SurfaceControl; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.server.testutils.TestHandler; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + + +/** + * Tests for DisplayModeDirector.SkinThermalStatusObserver. Comply with changes described in + * b/266789924 + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SkinThermalStatusObserverTest { + private static final float FLOAT_TOLERANCE = 0.01f; + private static final int DISPLAY_ID = 1; + private static final int DISPLAY_ID_OTHER = 2; + + SkinThermalStatusObserver mObserver; + + private RegisteringFakesInjector mInjector = new RegisteringFakesInjector(); + + private final TestHandler mHandler = new TestHandler(null); + private final FakeVoteStorage mStorage = new FakeVoteStorage(); + + @Before + public void setUp() { + mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler); + } + + @Test + public void testRegisterListenersOnObserve() { + // GIVEN thermal sensor is available + assertNull(mInjector.mThermalEventListener); + assertNull(mInjector.mDisplayListener); + // WHEN observe is called + mObserver.observe(); + // THEN thermal and display listeners are registered + assertEquals(mObserver, mInjector.mThermalEventListener); + assertEquals(mObserver, mInjector.mDisplayListener); + } + + @Test + public void testFailToRegisterThermalListenerOnObserve() { + // GIVEN thermal sensor is not available + mInjector = new RegisteringFakesInjector(false); + mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler); + // WHEN observe is called + mObserver.observe(); + // THEN nothing is registered + assertNull(mInjector.mThermalEventListener); + assertNull(mInjector.mDisplayListener); + } + + @Test + public void testNotifyWithDefaultVotesForCritical() { + // GIVEN 2 displays with no thermalThrottling config + mObserver.observe(); + assertEquals(0, mStorage.mVoteRegistry.size()); + + // WHEN thermal sensor notifies CRITICAL + mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_CRITICAL)); + mHandler.flush(); + + // THEN 2 votes are added to storage with (0,60) render refresh rate(default behaviour) + assertEquals(2, mStorage.mVoteRegistry.size()); + + SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(DISPLAY_ID); + assertEquals(1, displayVotes.size()); + + DisplayModeDirector.Vote vote = displayVotes.get( + DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE); + assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE); + assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE); + + SparseArray<DisplayModeDirector.Vote> otherDisplayVotes = mStorage.mVoteRegistry.get( + DISPLAY_ID_OTHER); + assertEquals(1, otherDisplayVotes.size()); + + vote = otherDisplayVotes.get(DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE); + assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE); + assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE); + } + + @Test + public void testNotifyWithDefaultVotesChangeFromCriticalToSevere() { + // GIVEN 2 displays with no thermalThrottling config AND temperature level CRITICAL + mObserver.observe(); + assertEquals(0, mStorage.mVoteRegistry.size()); + mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_CRITICAL)); + // WHEN thermal sensor notifies SEVERE + mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE)); + mHandler.flush(); + // THEN all votes with PRIORITY_SKIN_TEMPERATURE are removed from the storage + assertEquals(0, mStorage.mVoteRegistry.size()); + } + + @Test + public void testNotifyWithDefaultVotesForSevere() { + // GIVEN 2 displays with no thermalThrottling config + mObserver.observe(); + assertEquals(0, mStorage.mVoteRegistry.size()); + // WHEN thermal sensor notifies CRITICAL + mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE)); + mHandler.flush(); + // THEN nothing is added to the storage + assertEquals(0, mStorage.mVoteRegistry.size()); + } + + @Test + public void testNotifiesWithConfigVotes() { + // GIVEN 2 displays AND one has thermalThrottling config defined + SparseArray<SurfaceControl.RefreshRateRange> displayConfig = new SparseArray<>(); + displayConfig.put(Temperature.THROTTLING_MODERATE, + new SurfaceControl.RefreshRateRange(90.0f, 120.0f)); + SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> config = new SparseArray<>(); + config.put(DISPLAY_ID, displayConfig); + mInjector = new RegisteringFakesInjector(true, config); + mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler); + mObserver.observe(); + mObserver.onDisplayChanged(DISPLAY_ID); + assertEquals(0, mStorage.mVoteRegistry.size()); + // WHEN thermal sensor notifies temperature above configured + mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE)); + mHandler.flush(); + // THEN vote with refreshRate from config is added to the storage + assertEquals(1, mStorage.mVoteRegistry.size()); + SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(DISPLAY_ID); + assertEquals(1, displayVotes.size()); + DisplayModeDirector.Vote vote = displayVotes.get( + DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE); + assertEquals(90, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE); + assertEquals(120, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE); + } + + private static Temperature createTemperature(@Temperature.ThrottlingStatus int status) { + return new Temperature(40.0f, Temperature.TYPE_SKIN, "test_temp", status); + } + + + private static class RegisteringFakesInjector extends DisplayModeDirectorTest.FakesInjector { + private IThermalEventListener mThermalEventListener; + private DisplayManager.DisplayListener mDisplayListener; + + private final boolean mRegisterThermalListener; + private final SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> mOverriddenConfig; + + + private RegisteringFakesInjector() { + this(true); + } + + private RegisteringFakesInjector(boolean registerThermalListener) { + this(registerThermalListener, new SparseArray<>()); + } + + private RegisteringFakesInjector(boolean registerThermalListener, + SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> overriddenConfig) { + mRegisterThermalListener = registerThermalListener; + mOverriddenConfig = overriddenConfig; + } + + @Override + public boolean registerThermalServiceListener(IThermalEventListener listener) { + mThermalEventListener = (mRegisterThermalListener ? listener : null); + return mRegisterThermalListener; + } + + @Override + public void registerDisplayListener(DisplayManager.DisplayListener listener, + Handler handler, long flag) { + mDisplayListener = listener; + } + + @Override + public Display[] getDisplays() { + return new Display[] {createDisplay(DISPLAY_ID), createDisplay(DISPLAY_ID_OTHER)}; + } + + @Override + public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { + SparseArray<SurfaceControl.RefreshRateRange> config = mOverriddenConfig.get(displayId); + if (config != null) { + displayInfo.refreshRateThermalThrottling = config; + return true; + } + return false; + } + } + + + private static class FakeVoteStorage implements DisplayModeDirector.BallotBox { + private final SparseArray<SparseArray<DisplayModeDirector.Vote>> mVoteRegistry = + new SparseArray<>(); + + @Override + public void vote(int displayId, int priority, DisplayModeDirector.Vote vote) { + SparseArray<DisplayModeDirector.Vote> votesPerDisplay = mVoteRegistry.get(displayId); + if (votesPerDisplay == null) { + votesPerDisplay = new SparseArray<>(); + mVoteRegistry.put(displayId, votesPerDisplay); + } + if (vote == null) { + votesPerDisplay.remove(priority); + } else { + votesPerDisplay.put(priority, vote); + } + if (votesPerDisplay.size() == 0) { + mVoteRegistry.remove(displayId); + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt index b2bfd2bf720c..b660926f1394 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -256,12 +256,16 @@ class KeyboardLayoutManagerTests { @Test fun testNewUi_getKeyboardLayoutsForInputDevice() { NewSettingsApiFlag(true).use { - val keyboardLayouts = - keyboardLayoutManager.getKeyboardLayoutsForInputDevice(keyboardDevice.identifier) - assertEquals( - "New UI: getKeyboardLayoutsForInputDevice API should always return empty array", - 0, - keyboardLayouts.size + val keyboardLayouts = keyboardLayoutManager.keyboardLayouts + assertNotEquals( + "New UI: getKeyboardLayoutsForInputDevice API should not return empty array", + 0, + keyboardLayouts.size + ) + assertTrue( + "New UI: getKeyboardLayoutsForInputDevice API should provide English(US) " + + "layout", + hasLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR) ) } } diff --git a/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java new file mode 100644 index 000000000000..1e73a45a0c22 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java @@ -0,0 +1,247 @@ +/* + * 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.media; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; +import android.media.AudioManager; +import android.media.AudioRoutesInfo; +import android.media.IAudioRoutesObserver; +import android.media.MediaRoute2Info; +import android.os.RemoteException; + +import com.android.internal.R; +import com.android.server.audio.AudioService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(JUnit4.class) +public class AudioPoliciesDeviceRouteControllerTest { + + private static final String ROUTE_NAME_DEFAULT = "default"; + private static final String ROUTE_NAME_DOCK = "dock"; + private static final String ROUTE_NAME_HEADPHONES = "headphones"; + + private static final int VOLUME_SAMPLE_1 = 25; + + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + private AudioManager mAudioManager; + @Mock + private AudioService mAudioService; + @Mock + private DeviceRouteController.OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; + + @Captor + private ArgumentCaptor<IAudioRoutesObserver.Stub> mAudioRoutesObserverCaptor; + + private AudioPoliciesDeviceRouteController mController; + + private IAudioRoutesObserver.Stub mAudioRoutesObserver; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getText(anyInt())).thenReturn(ROUTE_NAME_DEFAULT); + + // Setting built-in speaker as default speaker. + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_SPEAKER; + when(mAudioService.startWatchingRoutes(mAudioRoutesObserverCaptor.capture())) + .thenReturn(audioRoutesInfo); + + mController = new AudioPoliciesDeviceRouteController( + mContext, mAudioManager, mAudioService, mOnDeviceRouteChangedListener); + + mAudioRoutesObserver = mAudioRoutesObserverCaptor.getValue(); + } + + @Test + public void getDeviceRoute_noSelectedRoutes_returnsDefaultDevice() { + MediaRoute2Info route2Info = mController.getDeviceRoute(); + + assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DEFAULT); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER); + } + + @Test + public void getDeviceRoute_audioRouteHasChanged_returnsRouteFromAudioService() { + when(mResources.getText(R.string.default_audio_route_name_headphones)) + .thenReturn(ROUTE_NAME_HEADPHONES); + + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; + callAudioRoutesObserver(audioRoutesInfo); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); + } + + @Test + public void getDeviceRoute_selectDevice_returnsSelectedRoute() { + when(mResources.getText(R.string.default_audio_route_name_dock_speakers)) + .thenReturn(ROUTE_NAME_DOCK); + + mController.selectRoute(MediaRoute2Info.TYPE_DOCK); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK); + } + + @Test + public void getDeviceRoute_hasSelectedAndAudioServiceRoutes_returnsSelectedRoute() { + when(mResources.getText(R.string.default_audio_route_name_headphones)) + .thenReturn(ROUTE_NAME_HEADPHONES); + when(mResources.getText(R.string.default_audio_route_name_dock_speakers)) + .thenReturn(ROUTE_NAME_DOCK); + + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; + callAudioRoutesObserver(audioRoutesInfo); + + mController.selectRoute(MediaRoute2Info.TYPE_DOCK); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK); + } + + @Test + public void getDeviceRoute_unselectRoute_returnsAudioServiceRoute() { + when(mResources.getText(R.string.default_audio_route_name_headphones)) + .thenReturn(ROUTE_NAME_HEADPHONES); + when(mResources.getText(R.string.default_audio_route_name_dock_speakers)) + .thenReturn(ROUTE_NAME_DOCK); + + mController.selectRoute(MediaRoute2Info.TYPE_DOCK); + + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; + callAudioRoutesObserver(audioRoutesInfo); + + mController.selectRoute(null); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); + } + + @Test + public void getDeviceRoute_selectRouteFails_returnsAudioServiceRoute() { + when(mResources.getText(R.string.default_audio_route_name_headphones)) + .thenReturn(ROUTE_NAME_HEADPHONES); + + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; + callAudioRoutesObserver(audioRoutesInfo); + + mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); + } + + @Test + public void selectRoute_selectWiredRoute_returnsTrue() { + assertThat(mController.selectRoute(MediaRoute2Info.TYPE_HDMI)).isTrue(); + } + + @Test + public void selectRoute_selectBluetoothRoute_returnsFalse() { + assertThat(mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)).isFalse(); + } + + @Test + public void selectRoute_unselectRoute_returnsTrue() { + assertThat(mController.selectRoute(null)).isTrue(); + } + + @Test + public void updateVolume_noSelectedRoute_deviceRouteVolumeChanged() { + when(mResources.getText(R.string.default_audio_route_name_headphones)) + .thenReturn(ROUTE_NAME_HEADPHONES); + + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; + callAudioRoutesObserver(audioRoutesInfo); + + mController.updateVolume(VOLUME_SAMPLE_1); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); + assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1); + } + + @Test + public void updateVolume_connectSelectedRouteLater_selectedRouteVolumeChanged() { + when(mResources.getText(R.string.default_audio_route_name_headphones)) + .thenReturn(ROUTE_NAME_HEADPHONES); + when(mResources.getText(R.string.default_audio_route_name_dock_speakers)) + .thenReturn(ROUTE_NAME_DOCK); + + AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo(); + audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; + callAudioRoutesObserver(audioRoutesInfo); + + mController.updateVolume(VOLUME_SAMPLE_1); + + mController.selectRoute(MediaRoute2Info.TYPE_DOCK); + + MediaRoute2Info route2Info = mController.getDeviceRoute(); + assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK); + assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1); + } + + /** + * Simulates {@link IAudioRoutesObserver.Stub#dispatchAudioRoutesChanged(AudioRoutesInfo)} + * from {@link AudioService}. This happens when there is a wired route change, + * like a wired headset being connected. + * + * @param audioRoutesInfo updated state of connected wired device + */ + private void callAudioRoutesObserver(AudioRoutesInfo audioRoutesInfo) { + try { + // this is a captured observer implementation + // from WiredRoutesController's AudioService#startWatchingRoutes call + mAudioRoutesObserver.dispatchAudioRoutesChanged(audioRoutesInfo); + } catch (RemoteException exception) { + // Should not happen since the object is mocked. + assertWithMessage("An unexpected RemoteException happened.").fail(); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java index 24ed42cab63a..24e48517f280 100644 --- a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java @@ -50,7 +50,7 @@ import java.util.Arrays; import java.util.Collection; @RunWith(Enclosed.class) -public class DeviceRouteControllerTest { +public class LegacyDeviceRouteControllerTest { private static final String DEFAULT_ROUTE_NAME = "default_route"; private static final String DEFAULT_HEADPHONES_NAME = "headphone"; @@ -97,7 +97,7 @@ public class DeviceRouteControllerTest { // Default route should be initialized even when AudioService returns null. when(mAudioService.startWatchingRoutes(any())).thenReturn(null); - DeviceRouteController deviceRouteController = new DeviceRouteController( + LegacyDeviceRouteController deviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, @@ -122,7 +122,7 @@ public class DeviceRouteControllerTest { AudioRoutesInfo fakeBluetoothAudioRoute = createFakeBluetoothAudioRoute(); when(mAudioService.startWatchingRoutes(any())).thenReturn(fakeBluetoothAudioRoute); - DeviceRouteController deviceRouteController = new DeviceRouteController( + LegacyDeviceRouteController deviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, @@ -236,7 +236,7 @@ public class DeviceRouteControllerTest { when(mResources.getText(mExpectedRouteNameResource)) .thenReturn(mExpectedRouteNameValue); - DeviceRouteController deviceRouteController = new DeviceRouteController( + LegacyDeviceRouteController deviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, @@ -269,7 +269,7 @@ public class DeviceRouteControllerTest { @Captor private ArgumentCaptor<IAudioRoutesObserver.Stub> mAudioRoutesObserverCaptor; - private DeviceRouteController mDeviceRouteController; + private LegacyDeviceRouteController mDeviceRouteController; private IAudioRoutesObserver.Stub mAudioRoutesObserver; @Before @@ -287,7 +287,7 @@ public class DeviceRouteControllerTest { when(mAudioService.startWatchingRoutes(mAudioRoutesObserverCaptor.capture())) .thenReturn(audioRoutesInfo); - mDeviceRouteController = new DeviceRouteController( + mDeviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index 4a2e5d7987f1..9fc46c563841 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -86,7 +86,6 @@ import android.service.notification.StatusBarNotification; import android.telecom.TelecomManager; import android.telephony.TelephonyManager; import android.text.format.DateUtils; -import android.util.Pair; import android.util.Range; import com.android.internal.app.ChooserActivity; @@ -187,7 +186,6 @@ public final class DataManagerTest { private ShortcutInfo mShortcutInfo; private TestInjector mInjector; private TestLooper mLooper; - private TestPerPackageThrottler mShortcutThrottler; @Before public void setUp() throws PackageManager.NameNotFoundException { @@ -277,9 +275,7 @@ public final class DataManagerTest { mInjector = new TestInjector(); mLooper = new TestLooper(); - mShortcutThrottler = new TestPerPackageThrottler(); - mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper(), - mShortcutThrottler); + mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper()); mDataManager.initialize(); when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), @@ -287,7 +283,10 @@ public final class DataManagerTest { mShortcutInfo = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, buildPerson()); - mockGetShortcuts(Collections.singletonList(mShortcutInfo)); + when(mShortcutServiceInternal.getShortcuts( + anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(), + anyInt(), anyInt(), anyInt(), anyInt())) + .thenReturn(Collections.singletonList(mShortcutInfo)); verify(mShortcutServiceInternal).addShortcutChangeCallback( mShortcutChangeCallbackCaptor.capture()); mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue(); @@ -973,7 +972,6 @@ public final class DataManagerTest { buildPerson()); ShortcutInfo shortcut3 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc3", buildPerson()); - mockGetShortcuts(List.of(shortcut1, shortcut2, shortcut3)); mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME, Arrays.asList(shortcut1, shortcut2, shortcut3), UserHandle.of(USER_ID_PRIMARY)); mShortcutChangeCallback.onShortcutsRemoved(TEST_PKG_NAME, @@ -1225,6 +1223,7 @@ public final class DataManagerTest { eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } } + @Test public void testUncacheOldestCachedShortcut_missingNotificationEvents() { mDataManager.onUserUnlocked(USER_ID_PRIMARY); @@ -1234,7 +1233,6 @@ public final class DataManagerTest { ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId, buildPerson()); shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); - mockGetShortcuts(Collections.singletonList(shortcut)); mShortcutChangeCallback.onShortcutsAddedOrUpdated( TEST_PKG_NAME, Collections.singletonList(shortcut), @@ -1254,6 +1252,7 @@ public final class DataManagerTest { eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } } + @Test public void testUncacheOldestCachedShortcut_legacyConversation() { mDataManager.onUserUnlocked(USER_ID_PRIMARY); @@ -1275,7 +1274,6 @@ public final class DataManagerTest { ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId, buildPerson()); shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); - mockGetShortcuts(Collections.singletonList(shortcut)); mShortcutChangeCallback.onShortcutsAddedOrUpdated( TEST_PKG_NAME, Collections.singletonList(shortcut), @@ -1313,8 +1311,7 @@ public final class DataManagerTest { mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter); byte[] payload = mDataManager.getBackupPayload(USER_ID_PRIMARY); - DataManager dataManager = new DataManager( - mContext, mInjector, mLooper.getLooper(), mShortcutThrottler); + DataManager dataManager = new DataManager(mContext, mInjector, mLooper.getLooper()); dataManager.onUserUnlocked(USER_ID_PRIMARY); dataManager.restore(USER_ID_PRIMARY, payload); ConversationInfo conversationInfo = dataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) @@ -1726,13 +1723,6 @@ public final class DataManagerTest { return (queryFlags & flag) != 0; } - private void mockGetShortcuts(List<ShortcutInfo> shortcutInfoList) { - when(mShortcutServiceInternal.getShortcuts( - anyInt(), anyString(), anyLong(), anyString(), any(), any(), any(), - anyInt(), anyInt(), anyInt(), anyInt())) - .thenReturn(shortcutInfoList); - } - // "Sends" a notification to a non-customized notification channel - the notification channel // is something generic like "messages" and the notification has a shortcut id private void sendGenericNotification() { @@ -1994,11 +1984,4 @@ public final class DataManagerTest { return mUsageStatsQueryHelper; } } - - private static class TestPerPackageThrottler implements PerPackageThrottler { - @Override - public void scheduleDebounced(Pair<String, Integer> pkgUserId, Runnable runnable) { - runnable.run(); - } - } } diff --git a/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java deleted file mode 100644 index 672cbb94e074..000000000000 --- a/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.people.data; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.util.Pair; - -import com.android.server.testutils.OffsettableClock; -import com.android.server.testutils.TestHandler; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.util.concurrent.atomic.AtomicBoolean; - -@RunWith(JUnit4.class) -public class PerPackageThrottlerImplTest { - private static final int DEBOUNCE_INTERVAL = 500; - private static final String PKG_ONE = "pkg_one"; - private static final String PKG_TWO = "pkg_two"; - private static final int USER_ID = 10; - - private final OffsettableClock mClock = new OffsettableClock.Stopped(); - private final TestHandler mTestHandler = new TestHandler(null, mClock); - private PerPackageThrottlerImpl mThrottler; - - @Before - public void setUp() { - mThrottler = new PerPackageThrottlerImpl(mTestHandler, DEBOUNCE_INTERVAL); - } - - @Test - public void scheduleDebounced() { - AtomicBoolean pkgOneRan = new AtomicBoolean(); - AtomicBoolean pkgTwoRan = new AtomicBoolean(); - - mThrottler.scheduleDebounced(new Pair<>(PKG_ONE, USER_ID), () -> pkgOneRan.set(true)); - mThrottler.scheduleDebounced(new Pair<>(PKG_ONE, USER_ID), () -> pkgOneRan.set(true)); - mThrottler.scheduleDebounced(new Pair<>(PKG_TWO, USER_ID), () -> pkgTwoRan.set(true)); - mThrottler.scheduleDebounced(new Pair<>(PKG_TWO, USER_ID), () -> pkgTwoRan.set(true)); - - assertFalse(pkgOneRan.get()); - assertFalse(pkgTwoRan.get()); - mClock.fastForward(DEBOUNCE_INTERVAL); - mTestHandler.timeAdvance(); - assertTrue(pkgOneRan.get()); - assertTrue(pkgTwoRan.get()); - } -} diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 0a718e329498..e65f8cf2a199 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -4007,6 +4007,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // TODO Check all other fields } + public void testLoadCorruptedShortcuts() throws Exception { + initService(); + + addPackage("com.android.chrome", 0, 0); + + ShortcutUser user = new ShortcutUser(mService, 0); + + File corruptedShortcutPackage = new File("/data/local/tmp/cts/content/", + "broken_shortcut.xml"); + assertNull(ShortcutPackage.loadFromFile(mService, user, corruptedShortcutPackage, false)); + } + public void testSaveCorruptAndLoadUser() throws Exception { // First, create some shortcuts and save. runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> { @@ -4096,11 +4108,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Save and corrupt the primary files. mService.saveDirtyInfo(); - try (Writer os = new FileWriter(mService.getUserFile(UserHandle.USER_SYSTEM))) { + try (Writer os = new FileWriter( + mService.getUserFile(UserHandle.USER_SYSTEM).getBaseFile())) { os.write("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<user locales=\"en\" last-app-scan-time2=\"14400000"); } - try (Writer os = new FileWriter(mService.getUserFile(USER_10))) { + try (Writer os = new FileWriter(mService.getUserFile(USER_10).getBaseFile())) { os.write("<?xml version='1.0' encoding='utf"); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 15fd73cf4674..01e56a0ddae6 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -2349,7 +2349,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { * can still be read. */ public void testLoadLegacySavedFile() throws Exception { - final File path = mService.getUserFile(USER_0); + final File path = mService.getUserFile(USER_0).getBaseFile(); path.getParentFile().mkdirs(); try (Writer w = new FileWriter(path)) { w.write(readTestAsset("shortcut/shortcut_legacy_file.xml")); diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java index c6a7fbcfb454..ee4b839dda5a 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java @@ -572,41 +572,14 @@ public class BatteryStatsImplTest { mBatteryStatsImpl.noteBluetoothScanStoppedFromSourceLocked(ws, true, 9000, 9000); mBatteryStatsImpl.noteBluetoothScanResultsFromSourceLocked(ws, 42, 9000, 9000); - - - final Parcel uidTrafficParcel1 = Parcel.obtain(); - final Parcel uidTrafficParcel2 = Parcel.obtain(); - - uidTrafficParcel1.writeInt(10042); - uidTrafficParcel1.writeLong(3000); - uidTrafficParcel1.writeLong(4000); - uidTrafficParcel1.setDataPosition(0); - uidTrafficParcel2.writeInt(10043); - uidTrafficParcel2.writeLong(5000); - uidTrafficParcel2.writeLong(8000); - uidTrafficParcel2.setDataPosition(0); - - List<UidTraffic> uidTrafficList = ImmutableList.of( - UidTraffic.CREATOR.createFromParcel(uidTrafficParcel1), - UidTraffic.CREATOR.createFromParcel(uidTrafficParcel2)); - - final Parcel btActivityEnergyInfoParcel = Parcel.obtain(); - btActivityEnergyInfoParcel.writeLong(1000); - btActivityEnergyInfoParcel.writeInt( - BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE); - btActivityEnergyInfoParcel.writeLong(9000); - btActivityEnergyInfoParcel.writeLong(8000); - btActivityEnergyInfoParcel.writeLong(12000); - btActivityEnergyInfoParcel.writeLong(0); - btActivityEnergyInfoParcel.writeTypedList(uidTrafficList); - btActivityEnergyInfoParcel.setDataPosition(0); - - BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR - .createFromParcel(btActivityEnergyInfoParcel); - - uidTrafficParcel1.recycle(); - uidTrafficParcel2.recycle(); - btActivityEnergyInfoParcel.recycle(); + BluetoothActivityEnergyInfo info = createBluetoothActivityEnergyInfo( + /* timestamp= */ 1000, + /* controllerTxTimeMs= */ 9000, + /* controllerRxTimeMs= */ 8000, + /* controllerIdleTimeMs= */ 12000, + /* controllerEnergyUsed= */ 0, + createUidTraffic(/* appUid= */ 10042, /* rxBytes= */ 3000, /* txBytes= */ 4000), + createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 5000, /* txBytes= */ 8000)); mBatteryStatsImpl.updateBluetoothStateLocked(info, -1, 1000, 1000); @@ -622,4 +595,105 @@ public class BatteryStatsImplTest { assertThat(uidStats.rxTimeMs).isEqualTo(7375); // Some scan time is treated as RX assertThat(uidStats.txTimeMs).isEqualTo(7666); // Some scan time is treated as TX } + + /** A regression test for b/266128651 */ + @Test + public void testGetNetworkActivityBytes_multipleUpdates() { + when(mPowerProfile.getAveragePower( + PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE)).thenReturn(3.0); + mBatteryStatsImpl.setOnBatteryInternal(true); + mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + + BluetoothActivityEnergyInfo info1 = createBluetoothActivityEnergyInfo( + /* timestamp= */ 10000, + /* controllerTxTimeMs= */ 9000, + /* controllerRxTimeMs= */ 8000, + /* controllerIdleTimeMs= */ 2000, + /* controllerEnergyUsed= */ 0, + createUidTraffic(/* appUid= */ 10042, /* rxBytes= */ 3000, /* txBytes= */ 4000), + createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 5000, /* txBytes= */ 8000)); + + mBatteryStatsImpl.updateBluetoothStateLocked(info1, -1, 1000, 1000); + + long totalRx1 = mBatteryStatsImpl.getNetworkActivityBytes( + BatteryStats.NETWORK_BT_RX_DATA, BatteryStats.STATS_SINCE_CHARGED); + long totalTx1 = mBatteryStatsImpl.getNetworkActivityBytes( + BatteryStats.NETWORK_BT_TX_DATA, BatteryStats.STATS_SINCE_CHARGED); + + assertThat(totalRx1).isEqualTo(8000); // 3000 + 5000 + assertThat(totalTx1).isEqualTo(12000); // 4000 + 8000 + + BluetoothActivityEnergyInfo info2 = createBluetoothActivityEnergyInfo( + /* timestamp= */ 20000, + /* controllerTxTimeMs= */ 19000, + /* controllerRxTimeMs= */ 18000, + /* controllerIdleTimeMs= */ 3000, + /* controllerEnergyUsed= */ 0, + createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 6000, /* txBytes= */ 9500), + createUidTraffic(/* appUid= */ 10044, /* rxBytes= */ 7000, /* txBytes= */ 9000)); + + mBatteryStatsImpl.updateBluetoothStateLocked(info2, -1, 2000, 2000); + + long totalRx2 = mBatteryStatsImpl.getNetworkActivityBytes( + BatteryStats.NETWORK_BT_RX_DATA, BatteryStats.STATS_SINCE_CHARGED); + long totalTx2 = mBatteryStatsImpl.getNetworkActivityBytes( + BatteryStats.NETWORK_BT_TX_DATA, BatteryStats.STATS_SINCE_CHARGED); + + assertThat(totalRx2).isEqualTo(16000); // 3000 + 6000 (updated) + 7000 (new) + assertThat(totalTx2).isEqualTo(22500); // 4000 + 9500 (updated) + 9000 (new) + + BluetoothActivityEnergyInfo info3 = createBluetoothActivityEnergyInfo( + /* timestamp= */ 30000, + /* controllerTxTimeMs= */ 20000, + /* controllerRxTimeMs= */ 20000, + /* controllerIdleTimeMs= */ 4000, + /* controllerEnergyUsed= */ 0, + createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 7000, /* txBytes= */ 9900), + createUidTraffic(/* appUid= */ 10044, /* rxBytes= */ 8000, /* txBytes= */ 10000)); + + mBatteryStatsImpl.updateBluetoothStateLocked(info3, -1, 2000, 2000); + + long totalRx3 = mBatteryStatsImpl.getNetworkActivityBytes( + BatteryStats.NETWORK_BT_RX_DATA, BatteryStats.STATS_SINCE_CHARGED); + long totalTx3 = mBatteryStatsImpl.getNetworkActivityBytes( + BatteryStats.NETWORK_BT_TX_DATA, BatteryStats.STATS_SINCE_CHARGED); + + assertThat(totalRx3).isEqualTo(18000); // 3000 + 7000 (updated) + 8000 (updated) + assertThat(totalTx3).isEqualTo(23900); // 4000 + 9900 (updated) + 10000 (updated) + } + + private UidTraffic createUidTraffic(int appUid, long rxBytes, long txBytes) { + final Parcel parcel = Parcel.obtain(); + parcel.writeInt(appUid); // mAppUid + parcel.writeLong(rxBytes); // mRxBytes + parcel.writeLong(txBytes); // mTxBytes + parcel.setDataPosition(0); + UidTraffic uidTraffic = UidTraffic.CREATOR.createFromParcel(parcel); + parcel.recycle(); + return uidTraffic; + } + + private BluetoothActivityEnergyInfo createBluetoothActivityEnergyInfo( + long timestamp, + long controllerTxTimeMs, + long controllerRxTimeMs, + long controllerIdleTimeMs, + long controllerEnergyUsed, + UidTraffic... uidTraffic) { + Parcel parcel = Parcel.obtain(); + parcel.writeLong(timestamp); // mTimestamp + parcel.writeInt( + BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE); // mBluetoothStackState + parcel.writeLong(controllerTxTimeMs); // mControllerTxTimeMs; + parcel.writeLong(controllerRxTimeMs); // mControllerRxTimeMs; + parcel.writeLong(controllerIdleTimeMs); // mControllerIdleTimeMs; + parcel.writeLong(controllerEnergyUsed); // mControllerEnergyUsed; + parcel.writeTypedList(ImmutableList.copyOf(uidTraffic)); // mUidTraffic + parcel.setDataPosition(0); + + BluetoothActivityEnergyInfo info = + BluetoothActivityEnergyInfo.CREATOR.createFromParcel(parcel); + parcel.recycle(); + return info; + } } diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java b/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java index 34e45c2096ea..178670e678f0 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java @@ -18,6 +18,7 @@ package com.android.server.power.stats; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN; +import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI; import static com.android.server.power.stats.CpuWakeupStats.WAKEUP_REASON_HALF_WINDOW_MS; import static com.android.server.power.stats.CpuWakeupStats.WAKEUP_RETENTION_MS; @@ -45,6 +46,7 @@ import java.util.concurrent.ThreadLocalRandom; @RunWith(AndroidJUnit4.class) public class CpuWakeupStatsTest { private static final String KERNEL_REASON_ALARM_IRQ = "120 test.alarm.device"; + private static final String KERNEL_REASON_WIFI_IRQ = "120 test.wifi.device"; private static final String KERNEL_REASON_UNKNOWN_IRQ = "140 test.unknown.device"; private static final String KERNEL_REASON_UNKNOWN = "free-form-reason test.alarm.device"; private static final String KERNEL_REASON_UNSUPPORTED = "-1 test.alarm.device"; @@ -68,22 +70,23 @@ public class CpuWakeupStatsTest { final Set<Long> timestamps = new HashSet<>(); final long firstWakeup = 453192; - obj.noteWakeupTimeAndReason(firstWakeup, 32, "unused"); + obj.noteWakeupTimeAndReason(firstWakeup, 32, KERNEL_REASON_UNKNOWN_IRQ); timestamps.add(firstWakeup); for (int i = 1; i < 1000; i++) { final long delta = mRandom.nextLong(WAKEUP_RETENTION_MS); if (timestamps.add(firstWakeup + delta)) { - obj.noteWakeupTimeAndReason(firstWakeup + delta, i, "unused"); + obj.noteWakeupTimeAndReason(firstWakeup + delta, i, KERNEL_REASON_UNKNOWN_IRQ); } } assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size()); - obj.noteWakeupTimeAndReason(firstWakeup + WAKEUP_RETENTION_MS + 1242, 231, "unused"); + obj.noteWakeupTimeAndReason(firstWakeup + WAKEUP_RETENTION_MS + 1242, 231, + KERNEL_REASON_UNKNOWN_IRQ); assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size()); for (int i = 0; i < 100; i++) { final long now = mRandom.nextLong(WAKEUP_RETENTION_MS + 1, 100 * WAKEUP_RETENTION_MS); - obj.noteWakeupTimeAndReason(now, i, "unused"); + obj.noteWakeupTimeAndReason(now, i, KERNEL_REASON_UNKNOWN_IRQ); assertThat(obj.mWakeupEvents.closestIndexOnOrBefore(now - WAKEUP_RETENTION_MS)) .isLessThan(0); } @@ -111,17 +114,45 @@ public class CpuWakeupStatsTest { assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_1)).isEqualTo(false); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_2)).isEqualTo(false); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_3)).isEqualTo(true); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_4)).isEqualTo(false); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_5)).isEqualTo(true); } @Test - public void alarmIrqAttributionCombined() { + public void wifiIrqAttributionSolo() { + final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); + final long wakeupTime = 12423121; + + obj.noteWakeupTimeAndReason(wakeupTime, 1, KERNEL_REASON_WIFI_IRQ); + + // Outside the window, so should be ignored. + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, + wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, + wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2); + // Should be attributed + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 3, TEST_UID_4, TEST_UID_5); + + final SparseArray<SparseBooleanArray> attribution = obj.mWakeupAttribution.get(wakeupTime); + assertThat(attribution).isNotNull(); + assertThat(attribution.size()).isEqualTo(1); + assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_WIFI)).isTrue(); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_1)).isEqualTo(false); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_2)).isEqualTo(false); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_3)).isEqualTo(false); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_4)).isEqualTo(true); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_5)).isEqualTo(true); + } + + @Test + public void alarmAndWifiIrqAttribution() { final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); final long wakeupTime = 92123210; obj.noteWakeupTimeAndReason(wakeupTime, 4, - KERNEL_REASON_UNKNOWN_IRQ + ":" + KERNEL_REASON_ALARM_IRQ); + KERNEL_REASON_WIFI_IRQ + ":" + KERNEL_REASON_ALARM_IRQ); + // Alarm activity // Outside the window, so should be ignored. obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1); @@ -132,16 +163,34 @@ public class CpuWakeupStatsTest { obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4, TEST_UID_5); + // Wifi activity + // Outside the window, so should be ignored. + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, + wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_4); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, + wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_3); + // Should be attributed + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 1, TEST_UID_2, + TEST_UID_5); + final SparseArray<SparseBooleanArray> attribution = obj.mWakeupAttribution.get(wakeupTime); assertThat(attribution).isNotNull(); assertThat(attribution.size()).isEqualTo(2); + assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_ALARM)).isTrue(); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_1)).isEqualTo(false); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_2)).isEqualTo(false); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_3)).isEqualTo(true); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_4)).isEqualTo(true); assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_5)).isEqualTo(true); - assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isTrue(); + + assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_WIFI)).isTrue(); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_1)).isEqualTo(true); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_2)).isEqualTo(true); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_3)).isEqualTo(false); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_4)).isEqualTo(false); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_5)).isEqualTo(true); } @Test @@ -151,9 +200,11 @@ public class CpuWakeupStatsTest { obj.noteWakeupTimeAndReason(wakeupTime, 24, KERNEL_REASON_UNKNOWN_IRQ); + assertThat(obj.mWakeupEvents.size()).isEqualTo(1); + // Unrelated subsystems, should not be attributed obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3); - obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4, + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 3, TEST_UID_4, TEST_UID_5); final SparseArray<SparseBooleanArray> attribution = obj.mWakeupAttribution.get(wakeupTime); @@ -165,42 +216,48 @@ public class CpuWakeupStatsTest { } @Test - public void unknownAttribution() { + public void unknownWakeupIgnored() { final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); final long wakeupTime = 72123210; obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN); - // Should be ignored as this type of wakeup is unsupported. + // Should be ignored as this type of wakeup is not known. + assertThat(obj.mWakeupEvents.size()).isEqualTo(0); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3); obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4); - // There should be nothing in the attribution map. + // Any nearby activity should not end up in the attribution map. assertThat(obj.mWakeupAttribution.size()).isEqualTo(0); } @Test - public void unsupportedAttribution() { + public void unsupportedWakeupIgnored() { final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); long wakeupTime = 970934; obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNSUPPORTED); // Should be ignored as this type of wakeup is unsupported. + assertThat(obj.mWakeupEvents.size()).isEqualTo(0); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3); obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4); - // There should be nothing in the attribution map. + // Any nearby activity should not end up in the attribution map. assertThat(obj.mWakeupAttribution.size()).isEqualTo(0); wakeupTime = 883124; obj.noteWakeupTimeAndReason(wakeupTime, 3, KERNEL_REASON_ABORT); // Should be ignored as this type of wakeup is unsupported. - obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 2, TEST_UID_1, TEST_UID_4); - obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 5, TEST_UID_3); + assertThat(obj.mWakeupEvents.size()).isEqualTo(0); + + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1, TEST_UID_4); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 5, TEST_UID_3); - // There should be nothing in the attribution map. + // Any nearby activity should not end up in the attribution map. assertThat(obj.mWakeupAttribution.size()).isEqualTo(0); } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index 6f37e601abce..ce076217f37b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -24,6 +24,8 @@ import static android.service.notification.NotificationListenerService.META_DATA import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT; import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; @@ -1201,28 +1203,11 @@ public class ManagedServicesTest extends UiServiceTestCase { mIpm, approvalLevel); loadXml(service); - List<String> allowedPackagesForUser0 = new ArrayList<>(); - allowedPackagesForUser0.add("this.is.a.package.name"); - allowedPackagesForUser0.add("another.package"); - allowedPackagesForUser0.add("secondary"); - - List<String> actual = service.getAllowedPackages(0); - assertEquals(3, actual.size()); - for (String pkg : allowedPackagesForUser0) { - assertTrue(actual.contains(pkg)); - } - - List<String> allowedPackagesForUser10 = new ArrayList<>(); - allowedPackagesForUser10.add("this.is.another.package"); - allowedPackagesForUser10.add("package"); - allowedPackagesForUser10.add("this.is.another.package"); - allowedPackagesForUser10.add("component"); - - actual = service.getAllowedPackages(10); - assertEquals(4, actual.size()); - for (String pkg : allowedPackagesForUser10) { - assertTrue(actual.contains(pkg)); - } + assertThat(service.getAllowedPackages(0)).containsExactly("this.is.a.package.name", + "another.package", "secondary"); + assertThat(service.getAllowedPackages(10)).containsExactly("this.is.another.package", + "package", "this.is.another.package", "component"); + assertThat(service.getAllowedPackages(999)).isEmpty(); } } @@ -1263,31 +1248,6 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test - public void testGetAllowedPackages() throws Exception { - ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, - mIpm, APPROVAL_BY_COMPONENT); - loadXml(service); - service.mApprovalLevel = APPROVAL_BY_PACKAGE; - loadXml(service); - - List<String> allowedPackages = new ArrayList<>(); - allowedPackages.add("this.is.a.package.name"); - allowedPackages.add("another.package"); - allowedPackages.add("secondary"); - allowedPackages.add("this.is.another.package"); - allowedPackages.add("package"); - allowedPackages.add("component"); - allowedPackages.add("bananas!"); - allowedPackages.add("non.user.set.package"); - - Set<String> actual = service.getAllowedPackages(); - assertEquals(allowedPackages.size(), actual.size()); - for (String pkg : allowedPackages) { - assertTrue(actual.contains(pkg)); - } - } - - @Test public void testOnUserRemoved() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, 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 f08d0f5f71a4..354420f46c2f 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -29,6 +29,7 @@ import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.Notification.FLAG_NO_CLEAR; import static android.app.Notification.FLAG_ONGOING_EVENT; import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; +import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; @@ -50,7 +51,6 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; - import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_MUTABLE; import static android.app.PendingIntent.FLAG_ONE_SHOT; @@ -237,6 +237,7 @@ import com.android.server.utils.quota.MultiRateLimiter; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerInternal; +import com.google.android.collect.Lists; import com.google.common.collect.ImmutableList; import org.junit.After; @@ -245,10 +246,13 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; +import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.io.BufferedInputStream; @@ -440,6 +444,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); mContext.addMockSystemService(NotificationManager.class, mMockNm); + doNothing().when(mContext).sendBroadcastAsUser(any(), any()); doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); setDpmAppOppsExemptFromDismissal(false); @@ -7828,6 +7833,75 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void onZenModeChanged_sendsBroadcasts() throws Exception { + when(mAmi.getCurrentUserId()).thenReturn(100); + when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); + when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { + @Override + public List<String> answer(InvocationOnMock invocation) { + int userId = invocation.getArgument(0); + switch (userId) { + case 100: + return Lists.newArrayList("a", "b", "c"); + case 101: + return Lists.newArrayList(); + case 102: + return Lists.newArrayList("b"); + default: + throw new IllegalArgumentException( + "Why would you ask for packages of userId " + userId + "?"); + } + } + }); + + mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null, + "testing!"); + waitForIdle(); + + InOrder inOrder = inOrder(mContext); + // Verify broadcasts for registered receivers + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( + new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null)); + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( + new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null)); + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( + new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null)); + + // Verify broadcast for packages that manage DND. + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( + ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( + ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( + ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); + inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( + ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102))); + } + + private static Intent eqIntent(Intent wanted) { + return ArgumentMatchers.argThat( + new ArgumentMatcher<Intent>() { + @Override + public boolean matches(Intent argument) { + return wanted.filterEquals(argument) + && wanted.getFlags() == argument.getFlags(); + } + + @Override + public String toString() { + return wanted.toString(); + } + }); + } + + @Test public void testAreNotificationsEnabledForPackage() throws Exception { mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 1ecd4a1ffd7e..79f69ee94a62 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -4131,17 +4131,26 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test - public void testTooManyGroups() { + public void testTooManyGroups_fromTargetApp() { + testTooManyGroups(/* fromTargetApp= */ true); + } + + @Test + public void testTooManyGroups_fromListener() { + testTooManyGroups(/* fromTargetApp= */ false); + } + + private void testTooManyGroups(boolean fromTargetApp) { for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) { NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i), String.valueOf(i)); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp); } try { NotificationChannelGroup group = new NotificationChannelGroup( String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT), String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT)); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp); fail("Allowed to create too many notification channel groups"); } catch (IllegalStateException e) { // great diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 6661e6a0a60d..49f215a83c2b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2897,7 +2897,7 @@ public class ActivityRecordTests extends WindowTestsBase { // Make the top one invisible, and try transferring the starting window from the top to the // bottom one. - activityTop.setVisibility(false, false); + activityTop.setVisibility(false); activityBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); waitUntilHandlersIdle(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index 3dcae91f5c89..0044e2e54b5a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -66,6 +66,7 @@ import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.DisplayInfo; import android.view.IDisplayWindowListener; +import android.view.WindowManager; import androidx.test.filters.MediumTest; @@ -456,13 +457,15 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { mAtm.mSupportsNonResizableMultiWindow = 0; // Supports on large screen. - tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp; + tda.getConfiguration().smallestScreenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; assertTrue(activity.supportsMultiWindow()); assertTrue(task.supportsMultiWindow()); // Not supports on small screen. - tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1; + tda.getConfiguration().smallestScreenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; assertFalse(activity.supportsMultiWindow()); assertFalse(task.supportsMultiWindow()); @@ -475,8 +478,10 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { new ActivityInfo.WindowLayout(0, 0, 0, 0, 0, // This is larger than the min dimensions device support in multi window, // the activity will not be supported in multi window if the device respects - /* minWidth= */(int) (mAtm.mLargeScreenSmallestScreenWidthDp * density), - /* minHeight= */(int) (mAtm.mLargeScreenSmallestScreenWidthDp * density)); + /* minWidth= */ + (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * density), + /* minHeight= */ + (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * density)); final ActivityRecord activity = new ActivityBuilder(mAtm) .setCreateTask(true) .setWindowLayout(windowLayout) @@ -501,13 +506,15 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { mAtm.mRespectsActivityMinWidthHeightMultiWindow = 0; // Ignore on large screen. - tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp; + tda.getConfiguration().smallestScreenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; assertTrue(activity.supportsMultiWindow()); assertTrue(task.supportsMultiWindow()); // Check on small screen. - tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1; + tda.getConfiguration().smallestScreenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; assertFalse(activity.supportsMultiWindow()); assertFalse(task.supportsMultiWindow()); @@ -518,7 +525,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { // This is smaller than the min dimensions device support in multi window, // the activity will be supported in multi window final float density = mContext.getResources().getDisplayMetrics().density; - final int supportedWidth = (int) (mAtm.mLargeScreenSmallestScreenWidthDp + final int supportedWidth = (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * mAtm.mMinPercentageMultiWindowSupportWidth * density); final ActivityInfo.WindowLayout windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0, @@ -531,15 +538,17 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { .build(); final Task task = activity.getTask(); final TaskDisplayArea tda = task.getDisplayArea(); - tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1; - tda.getConfiguration().screenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1; + tda.getConfiguration().smallestScreenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; + tda.getConfiguration().screenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; tda.getConfiguration().orientation = ORIENTATION_LANDSCAPE; assertFalse(activity.supportsMultiWindow()); assertFalse(task.supportsMultiWindow()); tda.getConfiguration().screenWidthDp = (int) Math.ceil( - mAtm.mLargeScreenSmallestScreenWidthDp + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP / mAtm.mMinPercentageMultiWindowSupportWidth); assertTrue(activity.supportsMultiWindow()); @@ -551,7 +560,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { // This is smaller than the min dimensions device support in multi window, // the activity will be supported in multi window final float density = mContext.getResources().getDisplayMetrics().density; - final int supportedHeight = (int) (mAtm.mLargeScreenSmallestScreenWidthDp + final int supportedHeight = (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * mAtm.mMinPercentageMultiWindowSupportHeight * density); final ActivityInfo.WindowLayout windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0, @@ -564,15 +573,17 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { .build(); final Task task = activity.getTask(); final TaskDisplayArea tda = task.getDisplayArea(); - tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1; - tda.getConfiguration().screenHeightDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1; + tda.getConfiguration().smallestScreenWidthDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; + tda.getConfiguration().screenHeightDp = + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; tda.getConfiguration().orientation = ORIENTATION_PORTRAIT; assertFalse(activity.supportsMultiWindow()); assertFalse(task.supportsMultiWindow()); tda.getConfiguration().screenHeightDp = (int) Math.ceil( - mAtm.mLargeScreenSmallestScreenWidthDp + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP / mAtm.mMinPercentageMultiWindowSupportHeight); assertTrue(activity.supportsMultiWindow()); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index 4d71b30d71e2..6d1312458ce2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -165,7 +165,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { assertTrue(mTask.isInChangeTransition()); // Changing visibility should cancel the change transition and become closing - mActivity.setVisibility(false, false); + mActivity.setVisibility(false); assertEquals(0, mDisplayContent.mChangingContainers.size()); assertFalse(mTask.isInChangeTransition()); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 6b814e678419..59cc4f5b0948 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -295,8 +295,8 @@ public class AppTransitionTests extends WindowTestsBase { dc2.prepareAppTransition(TRANSIT_CLOSE); // One activity window is visible for resuming & the other activity window is invisible // for finishing in different display. - activity1.setVisibility(true, false); - activity2.setVisibility(false, false); + activity1.setVisibility(true); + activity2.setVisibility(false); // Make sure each display is in animating stage. assertTrue(dc1.mOpeningApps.size() > 0); @@ -365,7 +365,7 @@ public class AppTransitionTests extends WindowTestsBase { dc.prepareAppTransition(TRANSIT_CLOSE); assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_CLOSE)); dc.mAppTransition.overridePendingAppTransitionRemote(adapter); - exitingActivity.setVisibility(false, false); + exitingActivity.setVisibility(false); assertTrue(dc.mClosingApps.size() > 0); // Make sure window is in animating stage before freeze, and cancel after freeze. diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java index 8cc362c1820c..17f6d51a74f3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java @@ -35,6 +35,8 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; +import android.app.WindowConfiguration; +import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; @@ -45,6 +47,7 @@ import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.util.DisplayMetrics; import android.view.ContentRecordingSession; +import android.view.Gravity; import android.view.Surface; import android.view.SurfaceControl; @@ -258,8 +261,17 @@ public class ContentRecorderTests extends WindowTestsBase { @Test public void testOnTaskBoundsConfigurationChanged_notifiesCallback() { + mTask.getRootTask().setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW); + final int recordedWidth = 333; final int recordedHeight = 999; + + final ActivityInfo info = new ActivityInfo(); + info.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */, + -1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */, + Gravity.NO_GRAVITY, recordedWidth, recordedHeight); + mTask.setMinDimensions(info); + // WHEN a recording is ongoing. mContentRecorder.setContentRecordingSession(mTaskSession); mContentRecorder.updateRecording(); @@ -267,7 +279,6 @@ public class ContentRecorderTests extends WindowTestsBase { // WHEN a configuration change arrives, and the recorded content is a different size. mTask.setBounds(new Rect(0, 0, recordedWidth, recordedHeight)); - mContentRecorder.onConfigurationChanged(mDefaultDisplay.getLastOrientation()); assertThat(mContentRecorder.isCurrentlyRecording()).isTrue(); // THEN content in the captured DisplayArea is scaled to fit the surface size. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index aaeae239024d..3379bebe6698 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1620,7 +1620,6 @@ public class DisplayContentTests extends WindowTestsBase { // If the rotated activity requests to show IME, the IME window should use the // transformation from activity to lay out in the same orientation. - mDisplayContent.setImeLayeringTarget(mAppWindow); LocalServices.getService(WindowManagerInternal.class).onToggleImeRequested(true /* show */, app.token, app.token, mDisplayContent.mDisplayId); assertTrue(asyncRotationController.isTargetToken(mImeWindow.mToken)); 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 d242a5f1af30..abbd3977d1a8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -117,6 +117,8 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; /** * Tests for Size Compatibility mode. @@ -172,6 +174,156 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testHorizontalReachabilityEnabledForTranslucentActivities() { + setUpDisplaySizeWithApp(2500, 1000); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + final LetterboxConfiguration config = mWm.mLetterboxConfiguration; + config.setTranslucentLetterboxingOverrideEnabled(true); + config.setLetterboxHorizontalPositionMultiplier(0.5f); + config.setIsHorizontalReachabilityEnabled(true); + + // Opaque activity + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + addWindowToActivity(mActivity); + mActivity.mRootWindowContainer.performSurfacePlacement(); + + // Translucent Activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + mTask.addChild(translucentActivity); + + spyOn(translucentActivity.mLetterboxUiController); + doReturn(true).when(translucentActivity.mLetterboxUiController) + .shouldShowLetterboxUi(any()); + + addWindowToActivity(translucentActivity); + translucentActivity.mRootWindowContainer.performSurfacePlacement(); + + final Function<ActivityRecord, Rect> innerBoundsOf = + (ActivityRecord a) -> { + final Rect bounds = new Rect(); + a.mLetterboxUiController.getLetterboxInnerBounds(bounds); + return bounds; + }; + final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity), + innerBoundsOf.apply(translucentActivity)); + final Runnable checkIsLeft = () -> assertThat( + innerBoundsOf.apply(translucentActivity).left).isEqualTo(0); + final Runnable checkIsRight = () -> assertThat( + innerBoundsOf.apply(translucentActivity).right).isEqualTo(2500); + final Runnable checkIsCentered = () -> assertThat( + innerBoundsOf.apply(translucentActivity).left > 0 + && innerBoundsOf.apply(translucentActivity).right < 2500).isTrue(); + + final Consumer<Integer> doubleClick = + (Integer x) -> { + mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x); + mActivity.mRootWindowContainer.performSurfacePlacement(); + }; + + // Initial state + checkIsCentered.run(); + + // Double-click left + doubleClick.accept(/* x */ 10); + checkLetterboxPositions.run(); + checkIsLeft.run(); + + // Double-click right + doubleClick.accept(/* x */ 1990); + checkLetterboxPositions.run(); + checkIsCentered.run(); + + // Double-click right + doubleClick.accept(/* x */ 1990); + checkLetterboxPositions.run(); + checkIsRight.run(); + + // Double-click left + doubleClick.accept(/* x */ 10); + checkLetterboxPositions.run(); + checkIsCentered.run(); + } + + @Test + public void testVerticalReachabilityEnabledForTranslucentActivities() { + setUpDisplaySizeWithApp(1000, 2500); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + final LetterboxConfiguration config = mWm.mLetterboxConfiguration; + config.setTranslucentLetterboxingOverrideEnabled(true); + config.setLetterboxVerticalPositionMultiplier(0.5f); + config.setIsVerticalReachabilityEnabled(true); + + // Opaque activity + prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); + addWindowToActivity(mActivity); + mActivity.mRootWindowContainer.performSurfacePlacement(); + + // Translucent Activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + mTask.addChild(translucentActivity); + + spyOn(translucentActivity.mLetterboxUiController); + doReturn(true).when(translucentActivity.mLetterboxUiController) + .shouldShowLetterboxUi(any()); + + addWindowToActivity(translucentActivity); + translucentActivity.mRootWindowContainer.performSurfacePlacement(); + + final Function<ActivityRecord, Rect> innerBoundsOf = + (ActivityRecord a) -> { + final Rect bounds = new Rect(); + a.mLetterboxUiController.getLetterboxInnerBounds(bounds); + return bounds; + }; + final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity), + innerBoundsOf.apply(translucentActivity)); + final Runnable checkIsTop = () -> assertThat( + innerBoundsOf.apply(translucentActivity).top).isEqualTo(0); + final Runnable checkIsBottom = () -> assertThat( + innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(2500); + final Runnable checkIsCentered = () -> assertThat( + innerBoundsOf.apply(translucentActivity).top > 0 + && innerBoundsOf.apply(translucentActivity).bottom < 2500).isTrue(); + + final Consumer<Integer> doubleClick = + (Integer y) -> { + mActivity.mLetterboxUiController.handleVerticalDoubleTap(y); + mActivity.mRootWindowContainer.performSurfacePlacement(); + }; + + // Initial state + checkIsCentered.run(); + + // Double-click top + doubleClick.accept(/* y */ 10); + checkLetterboxPositions.run(); + checkIsTop.run(); + + // Double-click bottom + doubleClick.accept(/* y */ 1990); + checkLetterboxPositions.run(); + checkIsCentered.run(); + + // Double-click bottom + doubleClick.accept(/* y */ 1990); + checkLetterboxPositions.run(); + checkIsBottom.run(); + + // Double-click top + doubleClick.accept(/* y */ 10); + checkLetterboxPositions.run(); + checkIsCentered.run(); + } + + @Test public void testApplyStrategyToTranslucentActivities() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); setUpDisplaySizeWithApp(2000, 1000); @@ -822,7 +974,7 @@ public class SizeCompatTests extends WindowTestsBase { .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) .build(); - assertFalse(activity.shouldCreateCompatDisplayInsets()); + assertTrue(activity.shouldCreateCompatDisplayInsets()); // The non-resizable activity should not be size compat because it is on a resizable task // in multi-window mode. @@ -855,7 +1007,7 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testShouldNotCreateCompatDisplayInsetsWhenRootActivityIsResizeable() { + public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() { setUpDisplaySizeWithApp(1000, 2500); // Make the task root resizable. @@ -864,7 +1016,7 @@ public class SizeCompatTests extends WindowTestsBase { // Create an activity on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - assertFalse(activity.shouldCreateCompatDisplayInsets()); + assertTrue(activity.shouldCreateCompatDisplayInsets()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index f4a266c11679..013c6d50d4e7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -545,7 +545,6 @@ public class SystemServicesTestRule implements TestRule { mDevEnableNonResizableMultiWindow = false; mMinPercentageMultiWindowSupportHeight = 0.3f; mMinPercentageMultiWindowSupportWidth = 0.5f; - mLargeScreenSmallestScreenWidthDp = 600; mSupportsNonResizableMultiWindow = 0; mRespectsActivityMinWidthHeightMultiWindow = 0; mForceResizableActivities = false; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index df3af7d2f4fa..49d8da1b2880 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -351,8 +351,8 @@ public class TaskFragmentTest extends WindowTestsBase { final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, mOrganizer); final ActivityRecord activity0 = taskFragment0.getTopMostActivity(); final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); - activity0.setVisibility(true /* visible */, false /* deferHidingClient */); - activity1.setVisibility(true /* visible */, false /* deferHidingClient */); + activity0.setVisibility(true); + activity1.setVisibility(true); spyOn(mAtm.mTaskFragmentOrganizerController); // Move activity to pinned. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 9cd80a34b714..5208e5a2dc2f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -535,6 +535,34 @@ public class TaskTests extends WindowTestsBase { assertEquals(reqBounds.height(), task.getBounds().height()); } + /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */ + @Test + public void testBoundsOnModeChangeFreeformToFullscreen() { + DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay(); + Task rootTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true) + .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + Task task = rootTask.getBottomMostTask(); + task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); + DisplayInfo info = new DisplayInfo(); + display.mDisplay.getDisplayInfo(info); + final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight); + final Rect freeformBounds = new Rect(fullScreenBounds); + freeformBounds.inset((int) (freeformBounds.width() * 0.2), + (int) (freeformBounds.height() * 0.2)); + task.setBounds(freeformBounds); + + assertEquals(freeformBounds, task.getBounds()); + + // FULLSCREEN inherits bounds + rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + assertEquals(fullScreenBounds, task.getBounds()); + assertEquals(freeformBounds, task.mLastNonFullscreenBounds); + + // FREEFORM restores bounds + rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM); + assertEquals(freeformBounds, task.getBounds()); + } + /** * Tests that a task with forced orientation has orientation-consistent bounds within the * parent. diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index fec079b7b15b..7e4a9de950e5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -30,6 +30,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -39,6 +42,7 @@ import android.graphics.Insets; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.util.DisplayMetrics; +import android.util.TypedValue; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; @@ -47,6 +51,8 @@ import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntr import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; class TestDisplayContent extends DisplayContent { @@ -197,10 +203,21 @@ class TestDisplayContent extends DisplayContent { MockitoAnnotations.initMocks(this); doReturn(mMockContext).when(mService.mContext).createConfigurationContext(any()); doReturn(mResources).when(mMockContext).getResources(); - doReturn(valueDp * mDisplayMetrics.density) - .when(mResources) - .getDimension( - com.android.internal.R.dimen.default_minimal_size_resizable_task); + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock i) { + Object[] args = i.getArguments(); + TypedValue v = (TypedValue) args[1]; + v.type = TypedValue.TYPE_DIMENSION; + v.data = TypedValue.createComplexDimension(valueDp, + TypedValue.COMPLEX_UNIT_DIP); + return null; + } + } + ).when(mResources).getValue( + eq(com.android.internal.R.dimen.default_minimal_size_resizable_task), + any(TypedValue.class), eq(true)); return this; } Builder setDeviceStateController(@NonNull DeviceStateController deviceStateController) { 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 3f14217b7a18..048e2ccc82b4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; @@ -1376,6 +1377,9 @@ public class TransitionTests extends WindowTestsBase { enteringAnimReports.clear(); closeTransition.finishTransition(); + assertEquals(ActivityTaskManagerService.APP_SWITCH_DISALLOW, mAtm.getBalAppSwitchesState()); + assertFalse(activity1.app.hasActivityInVisibleTask()); + verify(snapshotController, times(1)).recordSnapshot(eq(task1), eq(false)); assertTrue(enteringAnimReports.contains(activity2)); } @@ -1696,7 +1700,8 @@ public class TransitionTests extends WindowTestsBase { @Test public void testTransitionVisibleChange() { registerTestTransitionPlayer(); - final ActivityRecord app = createActivityRecord(mDisplayContent); + final ActivityRecord app = createActivityRecord( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */, app.mTransitionController, mWm.mSyncEngine); app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE); @@ -1746,7 +1751,8 @@ public class TransitionTests extends WindowTestsBase { @Test public void testVisibleChange_snapshot() { registerTestTransitionPlayer(); - final ActivityRecord app = createActivityRecord(mDisplayContent); + final ActivityRecord app = createActivityRecord( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */, app.mTransitionController, mWm.mSyncEngine); app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE); diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java index 2fccb88ad8de..75a8dd822914 100644 --- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java @@ -92,11 +92,11 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testRemoveFinishingInvisibleActivityFromUnknown() { - final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent); + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); activity.finishing = true; activity.setVisibleRequested(true); - activity.setVisibility(false, false); + activity.setVisibility(false); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 3aee2cd5fac1..33067df0c8f3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -914,15 +914,15 @@ public class WindowStateTests extends WindowTestsBase { final WindowState app = createWindow(null, TYPE_APPLICATION, "app", uid); app.mActivityRecord.setVisible(false); - app.mActivityRecord.setVisibility(false /* visible */, false /* deferHidingClient */); + app.mActivityRecord.setVisibility(false); assertFalse(mAtm.hasActiveVisibleWindow(uid)); - app.mActivityRecord.setVisibility(true /* visible */, false /* deferHidingClient */); + app.mActivityRecord.setVisibility(true); assertTrue(mAtm.hasActiveVisibleWindow(uid)); // Make the activity invisible and add a visible toast. The uid should have no active // visible window because toast can be misused by legacy app to bypass background check. - app.mActivityRecord.setVisibility(false /* visible */, false /* deferHidingClient */); + app.mActivityRecord.setVisibility(false); final WindowState overlay = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay", uid); final WindowState toast = createWindow(null, TYPE_TOAST, app.mToken, "toast", uid); toast.onSurfaceShownChanged(true); @@ -1157,12 +1157,12 @@ public class WindowStateTests extends WindowTestsBase { public void testRequestedVisibility() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); app.mActivityRecord.setVisible(false); - app.mActivityRecord.setVisibility(false /* visible */, false /* deferHidingClient */); + app.mActivityRecord.setVisibility(false); assertFalse(app.isVisibleRequested()); // It doesn't have a surface yet, but should still be visible requested. app.setHasSurface(false); - app.mActivityRecord.setVisibility(true /* visible */, false /* deferHidingClient */); + app.mActivityRecord.setVisibility(true); assertFalse(app.isVisible()); assertTrue(app.isVisibleRequested()); diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java index 2c5fcb86b0c5..68067d27a0a5 100644 --- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java +++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java @@ -191,9 +191,9 @@ public final class UsbGadgetHidl implements UsbGadgetHal { public void reset(long transactionId) { try { synchronized(mGadgetProxyLock) { - if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) { - android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy = - android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy); + if (android.hardware.usb.gadget.V1_1.IUsbGadget.castFrom(mGadgetProxy) != null) { + android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxy = + android.hardware.usb.gadget.V1_1.IUsbGadget.castFrom(mGadgetProxy); gadgetProxy.reset(); } } diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java index 97538c1c833f..50f2ad4561cc 100644 --- a/telecomm/java/android/telecom/CallControl.java +++ b/telecomm/java/android/telecom/CallControl.java @@ -294,18 +294,21 @@ public final class CallControl { /** * Raises an event to the {@link android.telecom.InCallService} implementations tracking this * call via {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}. - * These events and the associated extra keys for the {@code Bundle} parameter are defined - * in Android X. This API is used to relay additional information about a call other than - * what is specified in the {@link android.telecom.CallAttributes} to - * {@link android.telecom.InCallService}s. This might include, for example, a change to the list - * of participants in a meeting, or the name of the speakers who have their hand raised. Where - * appropriate, the {@link InCallService}s tracking this call may choose to render this - * additional information about the call. An automotive calling UX, for example may have enough - * screen real estate to indicate the number of participants in a meeting, but to prevent - * distractions could suppress the list of participants. + * These events and the associated extra keys for the {@code Bundle} parameter are mutually + * defined by a VoIP application and {@link android.telecom.InCallService}. This API is used to + * relay additional information about a call other than what is specified in the + * {@link android.telecom.CallAttributes} to {@link android.telecom.InCallService}s. This might + * include, for example, a change to the list of participants in a meeting, or the name of the + * speakers who have their hand raised. Where appropriate, the {@link InCallService}s tracking + * this call may choose to render this additional information about the call. An automotive + * calling UX, for example may have enough screen real estate to indicate the number of + * participants in a meeting, but to prevent distractions could suppress the list of + * participants. * - * @param event that is defined in AndroidX (ex. The number of participants changed) - * @param extras the updated value in relation to the event (ex. 4 participants) + * @param event a string event identifier agreed upon between a VoIP application and an + * {@link android.telecom.InCallService} + * @param extras a {@link android.os.Bundle} containing information about the event, as agreed + * upon between a VoIP application and {@link android.telecom.InCallService}. */ public void sendEvent(@NonNull String event, @NonNull Bundle extras) { Objects.requireNonNull(event); diff --git a/telecomm/java/android/telecom/CallEventCallback.java b/telecomm/java/android/telecom/CallEventCallback.java index d96c406c4294..a41c0113e933 100644 --- a/telecomm/java/android/telecom/CallEventCallback.java +++ b/telecomm/java/android/telecom/CallEventCallback.java @@ -60,14 +60,17 @@ public interface CallEventCallback { /** * Informs this {@link android.telecom.CallEventCallback} on events raised from a - * {@link android.telecom.InCallService} presenting this call. The event key and extra values - * are defined in AndroidX. This enables alternative calling surfaces, such as an automotive - * UI, to relay requests to perform other non-standard call actions to the app. For example, - * an automotive calling solution may offer the ability for the user to raise their hand - * during a meeting. + * {@link android.telecom.InCallService} presenting this call. These events and the + * associated extra keys for the {@code Bundle} parameter are mutually defined by a VoIP + * application and {@link android.telecom.InCallService}. This enables alternative calling + * surfaces, such as an automotive UI, to relay requests to perform other non-standard call + * actions to the app. For example, an automotive calling solution may offer the ability for + * the user to raise their hand during a meeting. * - * @param event that is defined in AndroidX (ex. the number of participants changed) - * @param extras the updated value in relation to the event (ex. 4 participants) + * @param event a string event identifier agreed upon between a VoIP application and an + * {@link android.telecom.InCallService} + * @param extras a {@link android.os.Bundle} containing information about the event, as agreed + * upon between a VoIP application and {@link android.telecom.InCallService}. */ void onEvent(@NonNull String event, @NonNull Bundle extras); } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 9170117f39e0..e39af5aa3327 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -895,9 +895,13 @@ public class TelecomManager { "android.telecom.extra.NOTIFICATION_PHONE_NUMBER"; /** - * The intent to clear missed calls. + * Included in the extras of the {@link #ACTION_SHOW_MISSED_CALLS_NOTIFICATION}, provides a + * pending intent which can be used to clear the missed calls notification and mark unread + * missed call log entries as read. * @hide + * @deprecated Use {@link #cancelMissedCallsNotification()} instead. */ + @Deprecated @SystemApi public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT"; @@ -2262,9 +2266,10 @@ public class TelecomManager { } /** - * Removes the missed-call notification if one is present. + * Removes the missed-call notification if one is present and marks missed calls in the call + * log as read. * <p> - * Requires that the method-caller be set as the system dialer app. + * Requires that the method-caller be set as the default dialer app. * </p> */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 77af95619492..bf12b9cce302 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -537,10 +537,9 @@ public class CarrierConfigManager { /** * CDMA activation goes through OTASP. - * <p> - * TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum - * (NONE, HFA, OTASP). */ + // TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum + // (NONE, HFA, OTASP). public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; @@ -7609,6 +7608,55 @@ public class CarrierConfigManager { public static final String KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL = KEY_PREFIX + "emergency_requires_volte_enabled_bool"; + /** + * This values indicates that the cross SIM redialing timer shall be disabled. + * + * @see #KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT + * @see #KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT + * @hide + */ + public static final int REDIAL_TIMER_DISABLED = 0; + + /** + * A timer to guard the max attempting time on current SIM slot so that modem will not + * stuck in current SIM slot for long time. On timer expiry, if emergency call on the + * other SIM slot is preferable, telephony shall cancel the emergency call and place the + * call on the other SIM slot. If this value is set to {@link #REDIAL_TIMER_DISABLED}, then + * the timer will never be started and domain selection continues on the current SIM slot. + * This value should be greater than the value of {@link #KEY_EMERGENCY_SCAN_TIMER_SEC_INT}. + * + * The default value for the timer is 120 seconds. + * @hide + */ + public static final String KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT = + KEY_PREFIX + "cross_stack_redial_timer_sec_int"; + + /** + * If emergency calls are only allowed with normal-registered service and UE should get + * normal service in a short time with acquired band information, telephony + * expects dialing emergency call will be completed in a short time. + * If dialing is not completed with in a certain timeout, telephony shall place on + * another SIM slot. If this value is set to {@link #REDIAL_TIMER_DISABLED}, then the timer + * will never be started and domain selection continues on the current SIM slot. + * The timer shall be started for the first trial of each subscription and shall be ignored + * in the roaming networks and non-domestic networks. + * + * The default value for the timer is {@link #REDIAL_TIMER_DISABLED}. + * @hide + */ + public static final String KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT = + KEY_PREFIX + "quick_cross_stack_redial_timer_sec_int"; + + /** + * Indicates whether the quick cross stack redial timer will be triggered only when + * the device is registered to the network. + * + * The default value is {@code true}. + * @hide + */ + public static final String KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL = + KEY_PREFIX + "start_quick_cross_stack_redial_timer_when_registered_bool"; + private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putBoolean(KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL, false); @@ -7675,6 +7723,10 @@ public class CarrierConfigManager { defaults.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, false); defaults.putStringArray(KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY, new String[0]); + defaults.putInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT, 120); + defaults.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, REDIAL_TIMER_DISABLED); + defaults.putBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL, + true); return defaults; } diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java index 3b4cf75e7919..1cfd22cc4d65 100644 --- a/telephony/java/android/telephony/PreciseDisconnectCause.java +++ b/telephony/java/android/telephony/PreciseDisconnectCause.java @@ -235,6 +235,23 @@ public final class PreciseDisconnectCause { /** Call failed/dropped because of a network detach. */ public static final int NETWORK_DETACH = 261; + /** + * Dialing emergency calls is currently unavailable. + * The call should be redialed on the other subscription silently. + * If there is no other subscription available, the call may be redialed + * on this subscription again. + * @hide + */ + public static final int EMERGENCY_TEMP_FAILURE = 325; + /** + * Dialing emergency calls is currently unavailable. + * The call should be redialed on the other subscription silently. + * Even if there is no other subscription available, the call should not + * be redialed on this subscription again. + * @hide + */ + public static final int EMERGENCY_PERM_FAILURE = 326; + /** Mobile station (MS) is locked until next power cycle. */ public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; /** Drop call. */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 3e2c7c4e5142..758372adab1d 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -3964,7 +3964,12 @@ public class SubscriptionManager { /** @hide */ public static void invalidateActiveDataSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY); + if (isSubscriptionManagerServiceEnabled()) { + PropertyInvalidatedCache.invalidateCache( + CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY); + } else { + PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY); + } } /** @hide */ diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index 9dc4bf034e66..9c3460c124ba 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -317,7 +317,8 @@ fun FlickerTest.replacesLayer( assertion.then().isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) } if (ignoreSplashscreen) { - assertion.then().isSplashScreenVisibleFor(newLayer, isOptional = true) + assertion.then().isSplashScreenVisibleFor( + ComponentNameMatcher(newLayer.packageName, className = ""), isOptional = true) } assertion.then().isVisible(newLayer) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt index 6005a81aac9e..786bb32096ad 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt @@ -16,9 +16,10 @@ package com.android.server.wm.flicker.launch +import android.os.SystemClock import android.platform.test.annotations.Postsubmit import android.tools.device.apphelpers.CameraAppHelper -import android.tools.device.flicker.annotation.FlickerServiceCompatible +import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.FlickerTest @@ -54,13 +55,14 @@ import org.junit.runners.Parameterized * ``` */ @RequiresDevice -@FlickerServiceCompatible @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) { private val cameraApp = CameraAppHelper(instrumentation) + override val testApp: StandardAppHelper + get() = cameraApp override val transition: FlickerBuilder.() -> Unit get() = { @@ -70,6 +72,7 @@ class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) : } transitions { device.pressKeyCode(KeyEvent.KEYCODE_POWER) + SystemClock.sleep(100) device.pressKeyCode(KeyEvent.KEYCODE_POWER) wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(cameraApp).waitForAndVerify() } diff --git a/tests/Input/src/com/android/test/input/MotionPredictorTest.kt b/tests/Input/src/com/android/test/input/MotionPredictorTest.kt index 8b1b06fe40e8..24a567130ff0 100644 --- a/tests/Input/src/com/android/test/input/MotionPredictorTest.kt +++ b/tests/Input/src/com/android/test/input/MotionPredictorTest.kt @@ -124,14 +124,12 @@ class MotionPredictorTest { predictor.record(moveEvent) val predicted = predictor.predict(Duration.ofMillis(8).toNanos()) - assertEquals(1, predicted.size) - val event = predicted[0] - assertNotNull(event) + assertNotNull(predicted) // Prediction will happen for t=12 (since it is the next input interval after the requested // time, 8, plus the model offset, 1). - assertEquals(12, event.eventTime) - assertEquals(30f, event.x, /*delta=*/5f) - assertEquals(60f, event.y, /*delta=*/15f) + assertEquals(12, predicted!!.eventTime) + assertEquals(30f, predicted.x, /*delta=*/5f) + assertEquals(60f, predicted.y, /*delta=*/15f) } } diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java index 573b3b695a90..d2708ad47712 100644 --- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java +++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java @@ -42,6 +42,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.uiautomator.By; import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; import androidx.test.uiautomator.Until; import org.junit.After; @@ -74,7 +75,7 @@ public final class NotificationTest { // This is for AOSP System UI for phones. When testing customized System UI, please modify here. private static final BySelector REPLY_SEND_BUTTON_SELECTOR = - By.res("com.android.systemui", "remote_input_send"); + By.res("com.android.systemui", "remote_input_send").enabled(true); @Rule public UnlockScreenRule mUnlockScreenRule = new UnlockScreenRule(); @@ -119,7 +120,15 @@ public final class NotificationTest { mUiDevice.pressKeyCode(KeyEvent.KEYCODE_A); mUiDevice.pressKeyCode(KeyEvent.KEYCODE_B); mUiDevice.pressKeyCode(KeyEvent.KEYCODE_C); - mUiDevice.wait(Until.findObject(REPLY_SEND_BUTTON_SELECTOR.enabled(true)), TIMEOUT).click(); + UiObject2 sendButton = mUiDevice.wait( + Until.findObject(REPLY_SEND_BUTTON_SELECTOR), TIMEOUT); + if (sendButton == null) { + // If the screen is too small, sendButton may be hidden by IME. + // Dismiss IME and try again. + mUiDevice.pressBack(); + sendButton = mUiDevice.wait(Until.findObject(REPLY_SEND_BUTTON_SELECTOR), TIMEOUT); + } + sendButton.click(); // Verify that IME is gone. assertThat(mUiDevice.wait(Until.gone(By.pkg(getImePackage(mContext))), TIMEOUT)).isTrue(); } diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java index 2cdb94526839..7deb8c73d1fc 100644 --- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java @@ -86,7 +86,7 @@ public class ProtoLogImplTest { mFile = testContext.getFileStreamPath("tracing_test.dat"); //noinspection ResultOfMethodCallIgnored mFile.delete(); - mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader); + mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024); } @After diff --git a/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt b/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt index f529bf77f32a..229d0c8da6e9 100644 --- a/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt +++ b/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt @@ -97,8 +97,8 @@ class DrawingView(context: Context, attrs: AttributeSet) : View(context, attrs) } // Draw predictions. Convert to nanos and hardcode to +20ms into the future - val predictionList = predictor.predict(eventTime * 1000000 + 20000000) - for (prediction in predictionList) { + val prediction = predictor.predict(eventTime * 1000000 + 20000000) + if (prediction != null) { val realEvents = events.get(prediction.deviceId)!! drawLine(canvas, realEvents[realEvents.size - 1], prediction, predictionPaint) } diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt index 387564437b5f..e079b6d5e4db 100644 --- a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt +++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt @@ -80,10 +80,10 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context spinner.adapter = adapter spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long ) { setImage(position) } @@ -108,7 +108,7 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context if (selectedImage == position) return selectedImage = position val source = ImageDecoder.createSource(resources.assets, - "gainmaps/${gainmapImages[position]}") + "gainmaps/${gainmapImages[position]}") doDecode(source) } @@ -137,16 +137,16 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context gainmapVisualizer = map } else { gainmapVisualizer = Bitmap.createBitmap(map.width, map.height, - Bitmap.Config.ARGB_8888) + Bitmap.Config.ARGB_8888) val canvas = Canvas(gainmapVisualizer!!) val paint = Paint() paint.colorFilter = ColorMatrixColorFilter( - floatArrayOf( - 0f, 0f, 0f, 1f, 0f, - 0f, 0f, 0f, 1f, 0f, - 0f, 0f, 0f, 1f, 0f, - 0f, 0f, 0f, 0f, 255f - ) + floatArrayOf( + 0f, 0f, 0f, 1f, 0f, + 0f, 0f, 0f, 1f, 0f, + 0f, 0f, 0f, 1f, 0f, + 0f, 0f, 0f, 0f, 255f + ) ) canvas.drawBitmap(map, 0f, 0f, paint) canvas.setBitmap(null) @@ -174,8 +174,14 @@ class GainmapImage(context: Context, attrs: AttributeSet?) : FrameLayout(context if (bitmap == null) return imageView.setImage(ImageSource.cachedBitmap(when (outputMode) { - R.id.output_hdr -> { bitmap!!.gainmap = gainmap; bitmap!! } - R.id.output_sdr -> { bitmap!!.gainmap = null; bitmap!! } + R.id.output_hdr -> { + bitmap!!.gainmap = gainmap; bitmap!! + } + + R.id.output_sdr -> { + bitmap!!.gainmap = null; bitmap!! + } + R.id.output_gainmap -> gainmapVisualizer!! else -> throw IllegalStateException() })) diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk index 7b94e718fd0e..34a1b112d880 100644 --- a/tools/aapt2/Android.mk +++ b/tools/aapt2/Android.mk @@ -15,7 +15,7 @@ $(aapt2_results): .KATI_IMPLICIT_OUTPUTS := $(aapt2_results)-nocache $(aapt2_results): $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests --gtest_output=xml:$@ > /dev/null 2>&1 -$(call declare-0p-target,$(aapt2_results)) +$(call declare-1p-target,$(aapt2_results)) aapt2_results := diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp index e53ba3e18a86..a1df878df12e 100644 --- a/tools/codegen/Android.bp +++ b/tools/codegen/Android.bp @@ -9,7 +9,7 @@ package { java_binary_host { name: "codegen_cli", - manifest: "manifest.txt", + main_class: "com.android.codegen.MainKt", srcs: [ "src/**/*.kt", ], diff --git a/tools/codegen/BUILD.bazel b/tools/codegen/BUILD.bazel deleted file mode 100644 index c14046d674dc..000000000000 --- a/tools/codegen/BUILD.bazel +++ /dev/null @@ -1,21 +0,0 @@ -# TODO(b/245731902): auto-generate these with bp2build. -load("@rules_kotlin//kotlin:jvm_library.bzl", "kt_jvm_library") - -java_binary( - name = "codegen_cli", - main_class = "com.android.codegen.MainKt", - runtime_deps = [ - ":codegen_cli_kt_lib", - ], -) - -kt_jvm_library( - name = "codegen_cli_kt_lib", - srcs = glob(["src/**/*.kt"]), - deps = ["//external/javaparser"], -) - -kt_jvm_library( - name = "codegen-version-info", - srcs = glob(["src/**/SharedConstants.kt"]), -) diff --git a/tools/codegen/manifest.txt b/tools/codegen/manifest.txt deleted file mode 100644 index 6e1018ba6b55..000000000000 --- a/tools/codegen/manifest.txt +++ /dev/null @@ -1 +0,0 @@ -Main-class: com.android.codegen.MainKt diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.aidl index 6cc4cfe7dce5..f9c4829c8f93 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.aidl @@ -16,4 +16,4 @@ package android.net.wifi.sharedconnectivity.app; -parcelable TetherNetwork; +parcelable HotspotNetwork; diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java index 7b591d3a45bd..d3b7b12e5387 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java @@ -33,14 +33,14 @@ import java.util.Objects; import java.util.Set; /** - * A data class representing an Instant Tether network. + * A data class representing a hotspot network. * This class is used in IPC calls between the implementer of {@link SharedConnectivityService} and * the consumers of {@link com.android.wifitrackerlib}. * * @hide */ @SystemApi -public final class TetherNetwork implements Parcelable { +public final class HotspotNetwork implements Parcelable { /** * Remote device is connected to the internet via an unknown connection. */ @@ -71,33 +71,44 @@ public final class TetherNetwork implements Parcelable { NETWORK_TYPE_WIFI, NETWORK_TYPE_ETHERNET }) - public @interface NetworkType {} + public @interface NetworkType { + } private final long mDeviceId; - private final DeviceInfo mDeviceInfo; - @NetworkType private final int mNetworkType; + private final NetworkProviderInfo mNetworkProviderInfo; + @NetworkType + private final int mNetworkType; private final String mNetworkName; - @Nullable private final String mHotspotSsid; - @Nullable private final String mHotspotBssid; - @Nullable @SecurityType private final ArraySet<Integer> mHotspotSecurityTypes; + @Nullable + private final String mHotspotSsid; + @Nullable + private final String mHotspotBssid; + @Nullable + @SecurityType + private final ArraySet<Integer> mHotspotSecurityTypes; /** - * Builder class for {@link TetherNetwork}. + * Builder class for {@link HotspotNetwork}. */ public static final class Builder { private long mDeviceId = -1; - private DeviceInfo mDeviceInfo; - @NetworkType private int mNetworkType; + private NetworkProviderInfo mNetworkProviderInfo; + @NetworkType + private int mNetworkType; private String mNetworkName; - @Nullable private String mHotspotSsid; - @Nullable private String mHotspotBssid; - @Nullable @SecurityType private final ArraySet<Integer> mHotspotSecurityTypes = + @Nullable + private String mHotspotSsid; + @Nullable + private String mHotspotBssid; + @Nullable + @SecurityType + private final ArraySet<Integer> mHotspotSecurityTypes = new ArraySet<>(); /** * Set the remote device ID. * - * @param deviceId Locally unique ID for this Instant Tether network. + * @param deviceId Locally unique ID for this Hotspot network. * @return Returns the Builder object. */ @NonNull @@ -109,12 +120,12 @@ public final class TetherNetwork implements Parcelable { /** * Sets information about the device providing connectivity. * - * @param deviceInfo The device information object. + * @param networkProviderInfo The device information object. * @return Returns the Builder object. */ @NonNull - public Builder setDeviceInfo(@NonNull DeviceInfo deviceInfo) { - mDeviceInfo = deviceInfo; + public Builder setNetworkProviderInfo(@NonNull NetworkProviderInfo networkProviderInfo) { + mNetworkProviderInfo = networkProviderInfo; return this; } @@ -125,7 +136,7 @@ public final class TetherNetwork implements Parcelable { * @return Returns the Builder object. */ @NonNull - public Builder setNetworkType(@NetworkType int networkType) { + public Builder setHostNetworkType(@NetworkType int networkType) { mNetworkType = networkType; return this; } @@ -179,15 +190,15 @@ public final class TetherNetwork implements Parcelable { } /** - * Builds the {@link TetherNetwork} object. + * Builds the {@link HotspotNetwork} object. * - * @return Returns the built {@link TetherNetwork} object. + * @return Returns the built {@link HotspotNetwork} object. */ @NonNull - public TetherNetwork build() { - return new TetherNetwork( + public HotspotNetwork build() { + return new HotspotNetwork( mDeviceId, - mDeviceInfo, + mNetworkProviderInfo, mNetworkType, mNetworkName, mHotspotSsid, @@ -196,7 +207,7 @@ public final class TetherNetwork implements Parcelable { } } - private static void validate(long deviceId, int networkType, String networkName) { + private static void validate(long deviceId, @NetworkType int networkType, String networkName) { if (deviceId < 0) { throw new IllegalArgumentException("DeviceId must be set"); } @@ -209,9 +220,9 @@ public final class TetherNetwork implements Parcelable { } } - private TetherNetwork( + private HotspotNetwork( long deviceId, - DeviceInfo deviceInfo, + NetworkProviderInfo networkProviderInfo, @NetworkType int networkType, @NonNull String networkName, @Nullable String hotspotSsid, @@ -221,7 +232,7 @@ public final class TetherNetwork implements Parcelable { networkType, networkName); mDeviceId = deviceId; - mDeviceInfo = deviceInfo; + mNetworkProviderInfo = networkProviderInfo; mNetworkType = networkType; mNetworkName = networkName; mHotspotSsid = hotspotSsid; @@ -232,7 +243,7 @@ public final class TetherNetwork implements Parcelable { /** * Gets the remote device ID. * - * @return Returns the locally unique ID for this Instant Tether network. + * @return Returns the locally unique ID for this Hotspot network. */ public long getDeviceId() { return mDeviceId; @@ -241,11 +252,11 @@ public final class TetherNetwork implements Parcelable { /** * Gets information about the device providing connectivity. * - * @return Returns the information of the device providing the Instant Tether network. + * @return Returns the information of the device providing the Hotspot network. */ @NonNull - public DeviceInfo getDeviceInfo() { - return mDeviceInfo; + public NetworkProviderInfo getNetworkProviderInfo() { + return mNetworkProviderInfo; } /** @@ -254,7 +265,7 @@ public final class TetherNetwork implements Parcelable { * @return Returns the network type as represented by IntDef {@link NetworkType}. */ @NetworkType - public int getNetworkType() { + public int getHostNetworkType() { return mNetworkType; } @@ -301,11 +312,11 @@ public final class TetherNetwork implements Parcelable { @Override public boolean equals(Object obj) { - if (!(obj instanceof TetherNetwork)) return false; - TetherNetwork other = (TetherNetwork) obj; + if (!(obj instanceof HotspotNetwork)) return false; + HotspotNetwork other = (HotspotNetwork) obj; return mDeviceId == other.getDeviceId() - && Objects.equals(mDeviceInfo, other.getDeviceInfo()) - && mNetworkType == other.getNetworkType() + && Objects.equals(mNetworkProviderInfo, other.getNetworkProviderInfo()) + && mNetworkType == other.getHostNetworkType() && Objects.equals(mNetworkName, other.getNetworkName()) && Objects.equals(mHotspotSsid, other.getHotspotSsid()) && Objects.equals(mHotspotBssid, other.getHotspotBssid()) @@ -314,8 +325,8 @@ public final class TetherNetwork implements Parcelable { @Override public int hashCode() { - return Objects.hash(mDeviceId, mDeviceInfo, mNetworkName, mHotspotSsid, mHotspotBssid, - mHotspotSecurityTypes); + return Objects.hash(mDeviceId, mNetworkProviderInfo, mNetworkName, mHotspotSsid, + mHotspotBssid, mHotspotSecurityTypes); } @Override @@ -326,7 +337,7 @@ public final class TetherNetwork implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(mDeviceId); - mDeviceInfo.writeToParcel(dest, flags); + mNetworkProviderInfo.writeToParcel(dest, flags); dest.writeInt(mNetworkType); dest.writeString(mNetworkName); dest.writeString(mHotspotSsid); @@ -335,36 +346,36 @@ public final class TetherNetwork implements Parcelable { } /** - * Creates a {@link TetherNetwork} object from a parcel. + * Creates a {@link HotspotNetwork} object from a parcel. * * @hide */ @NonNull - public static TetherNetwork readFromParcel(@NonNull Parcel in) { - return new TetherNetwork(in.readLong(), DeviceInfo.readFromParcel(in), + public static HotspotNetwork readFromParcel(@NonNull Parcel in) { + return new HotspotNetwork(in.readLong(), NetworkProviderInfo.readFromParcel(in), in.readInt(), in.readString(), in.readString(), in.readString(), (ArraySet<Integer>) in.readArraySet(null)); } @NonNull - public static final Creator<TetherNetwork> CREATOR = new Creator<>() { + public static final Creator<HotspotNetwork> CREATOR = new Creator<>() { @Override - public TetherNetwork createFromParcel(Parcel in) { + public HotspotNetwork createFromParcel(Parcel in) { return readFromParcel(in); } @Override - public TetherNetwork[] newArray(int size) { - return new TetherNetwork[size]; + public HotspotNetwork[] newArray(int size) { + return new HotspotNetwork[size]; } }; @Override public String toString() { - return new StringBuilder("TetherNetwork[") + return new StringBuilder("HotspotNetwork[") .append("deviceId=").append(mDeviceId) .append(", networkType=").append(mNetworkType) - .append(", deviceInfo=").append(mDeviceInfo.toString()) + .append(", networkProviderInfo=").append(mNetworkProviderInfo.toString()) .append(", networkName=").append(mNetworkName) .append(", hotspotSsid=").append(mHotspotSsid) .append(", hotspotBssid=").append(mHotspotBssid) diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.aidl index c677a6c508ad..d32d15e7c058 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.aidl +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.aidl @@ -16,4 +16,4 @@ package android.net.wifi.sharedconnectivity.app; -parcelable TetherNetworkConnectionStatus; +parcelable HotspotNetworkConnectionStatus; diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java index 3cf44ed3ed32..69767f302bd8 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java @@ -28,23 +28,23 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * The status of a connection to an instant tether network after the client called - * {@link SharedConnectivityManager#connectTetherNetwork}. + * The status of a connection to a hotspot network after the client called + * {@link SharedConnectivityManager#connectHotspotNetwork}. * * @hide */ @SystemApi -public final class TetherNetworkConnectionStatus implements Parcelable { +public final class HotspotNetworkConnectionStatus implements Parcelable { /** * Connection status is unknown. */ - public static final int CONNECTION_STATUS_UNKNOWN = 0; + public static final int CONNECTION_STATUS_UNKNOWN = 0; /** * The connection is being initiated. */ - public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1; + public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1; /** * Device providing the hotspot failed to initiate it. @@ -102,22 +102,23 @@ public final class TetherNetworkConnectionStatus implements Parcelable { CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT, CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED, }) - public @interface ConnectionStatus {} + public @interface ConnectionStatus { + } - @ConnectionStatus private final int mStatus; - private final TetherNetwork mTetherNetwork; + @ConnectionStatus + private final int mStatus; + private final HotspotNetwork mHotspotNetwork; private final Bundle mExtras; /** - * Builder class for {@link TetherNetworkConnectionStatus}. + * Builder class for {@link HotspotNetworkConnectionStatus}. */ public static final class Builder { - @ConnectionStatus private int mStatus; - private TetherNetwork mTetherNetwork; + @ConnectionStatus + private int mStatus; + private HotspotNetwork mHotspotNetwork; private Bundle mExtras; - public Builder() {} - /** * Sets the status of the connection * @@ -130,13 +131,13 @@ public final class TetherNetworkConnectionStatus implements Parcelable { } /** - * Sets the {@link TetherNetwork} object of the connection. + * Sets the {@link HotspotNetwork} object of the connection. * * @return Returns the Builder object. */ @NonNull - public Builder setTetherNetwork(@NonNull TetherNetwork tetherNetwork) { - mTetherNetwork = tetherNetwork; + public Builder setHotspotNetwork(@NonNull HotspotNetwork hotspotNetwork) { + mHotspotNetwork = hotspotNetwork; return this; } @@ -152,20 +153,36 @@ public final class TetherNetworkConnectionStatus implements Parcelable { } /** - * Builds the {@link TetherNetworkConnectionStatus} object. + * Builds the {@link HotspotNetworkConnectionStatus} object. * - * @return Returns the built {@link TetherNetworkConnectionStatus} object. + * @return Returns the built {@link HotspotNetworkConnectionStatus} object. */ @NonNull - public TetherNetworkConnectionStatus build() { - return new TetherNetworkConnectionStatus(mStatus, mTetherNetwork, mExtras); + public HotspotNetworkConnectionStatus build() { + return new HotspotNetworkConnectionStatus(mStatus, mHotspotNetwork, mExtras); + } + } + + private static void validate(@ConnectionStatus int status) { + if (status != CONNECTION_STATUS_UNKNOWN + && status != CONNECTION_STATUS_ENABLING_HOTSPOT + && status != CONNECTION_STATUS_UNKNOWN_ERROR + && status != CONNECTION_STATUS_PROVISIONING_FAILED + && status != CONNECTION_STATUS_TETHERING_TIMEOUT + && status != CONNECTION_STATUS_TETHERING_UNSUPPORTED + && status != CONNECTION_STATUS_NO_CELL_DATA + && status != CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED + && status != CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT + && status != CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED) { + throw new IllegalArgumentException("Illegal connection status"); } } - private TetherNetworkConnectionStatus(@ConnectionStatus int status, TetherNetwork tetherNetwork, - Bundle extras) { + private HotspotNetworkConnectionStatus(@ConnectionStatus int status, + HotspotNetwork hotspotNetwork, Bundle extras) { + validate(status); mStatus = status; - mTetherNetwork = tetherNetwork; + mHotspotNetwork = hotspotNetwork; mExtras = extras; } @@ -180,13 +197,13 @@ public final class TetherNetworkConnectionStatus implements Parcelable { } /** - * Gets the {@link TetherNetwork} object of the connection. + * Gets the {@link HotspotNetwork} object of the connection. * - * @return Returns a TetherNetwork object. + * @return Returns a HotspotNetwork object. */ @NonNull - public TetherNetwork getTetherNetwork() { - return mTetherNetwork; + public HotspotNetwork getHotspotNetwork() { + return mHotspotNetwork; } /** @@ -201,15 +218,15 @@ public final class TetherNetworkConnectionStatus implements Parcelable { @Override public boolean equals(Object obj) { - if (!(obj instanceof TetherNetworkConnectionStatus)) return false; - TetherNetworkConnectionStatus other = (TetherNetworkConnectionStatus) obj; + if (!(obj instanceof HotspotNetworkConnectionStatus)) return false; + HotspotNetworkConnectionStatus other = (HotspotNetworkConnectionStatus) obj; return mStatus == other.getStatus() - && Objects.equals(mTetherNetwork, other.getTetherNetwork()); + && Objects.equals(mHotspotNetwork, other.getHotspotNetwork()); } @Override public int hashCode() { - return Objects.hash(mStatus, mTetherNetwork); + return Objects.hash(mStatus, mHotspotNetwork); } @Override @@ -220,39 +237,39 @@ public final class TetherNetworkConnectionStatus implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mStatus); - mTetherNetwork.writeToParcel(dest, flags); + mHotspotNetwork.writeToParcel(dest, flags); dest.writeBundle(mExtras); } /** - * Creates a {@link TetherNetworkConnectionStatus} object from a parcel. + * Creates a {@link HotspotNetworkConnectionStatus} object from a parcel. * * @hide */ @NonNull - public static TetherNetworkConnectionStatus readFromParcel(@NonNull Parcel in) { - return new TetherNetworkConnectionStatus(in.readInt(), - TetherNetwork.readFromParcel(in), in.readBundle()); + public static HotspotNetworkConnectionStatus readFromParcel(@NonNull Parcel in) { + return new HotspotNetworkConnectionStatus(in.readInt(), + HotspotNetwork.readFromParcel(in), in.readBundle()); } @NonNull - public static final Creator<TetherNetworkConnectionStatus> CREATOR = new Creator<>() { + public static final Creator<HotspotNetworkConnectionStatus> CREATOR = new Creator<>() { @Override - public TetherNetworkConnectionStatus createFromParcel(Parcel in) { + public HotspotNetworkConnectionStatus createFromParcel(Parcel in) { return readFromParcel(in); } @Override - public TetherNetworkConnectionStatus[] newArray(int size) { - return new TetherNetworkConnectionStatus[size]; + public HotspotNetworkConnectionStatus[] newArray(int size) { + return new HotspotNetworkConnectionStatus[size]; } }; @Override public String toString() { - return new StringBuilder("TetherNetworkConnectionStatus[") + return new StringBuilder("HotspotNetworkConnectionStatus[") .append("status=").append(mStatus) - .append("tether network=").append(mTetherNetwork.toString()) + .append("hotspot network=").append(mHotspotNetwork.toString()) .append("extras=").append(mExtras.toString()) .append("]").toString(); } diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java index fe23caae7f03..64412bc55fb2 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java @@ -64,21 +64,26 @@ public final class KnownNetwork implements Parcelable { NETWORK_SOURCE_NEARBY_SELF, NETWORK_SOURCE_CLOUD_SELF }) - public @interface NetworkSource {} + public @interface NetworkSource { + } - @NetworkSource private final int mNetworkSource; + @NetworkSource + private final int mNetworkSource; private final String mSsid; - @SecurityType private final ArraySet<Integer> mSecurityTypes; - private final DeviceInfo mDeviceInfo; + @SecurityType + private final ArraySet<Integer> mSecurityTypes; + private final NetworkProviderInfo mNetworkProviderInfo; /** * Builder class for {@link KnownNetwork}. */ public static final class Builder { - @NetworkSource private int mNetworkSource = -1; + @NetworkSource + private int mNetworkSource = -1; private String mSsid; - @SecurityType private final ArraySet<Integer> mSecurityTypes = new ArraySet<>(); - private android.net.wifi.sharedconnectivity.app.DeviceInfo mDeviceInfo; + @SecurityType + private final ArraySet<Integer> mSecurityTypes = new ArraySet<>(); + private NetworkProviderInfo mNetworkProviderInfo; /** * Sets the indicated source of the known network. @@ -120,12 +125,12 @@ public final class KnownNetwork implements Parcelable { * Sets the device information of the device providing connectivity. * Must be set if network source is {@link KnownNetwork#NETWORK_SOURCE_NEARBY_SELF}. * - * @param deviceInfo The device information object. + * @param networkProviderInfo The device information object. * @return Returns the Builder object. */ @NonNull - public Builder setDeviceInfo(@Nullable DeviceInfo deviceInfo) { - mDeviceInfo = deviceInfo; + public Builder setNetworkProviderInfo(@Nullable NetworkProviderInfo networkProviderInfo) { + mNetworkProviderInfo = networkProviderInfo; return this; } @@ -140,12 +145,13 @@ public final class KnownNetwork implements Parcelable { mNetworkSource, mSsid, mSecurityTypes, - mDeviceInfo); + mNetworkProviderInfo); } } - private static void validate(int networkSource, String ssid, Set<Integer> securityTypes, - DeviceInfo deviceInfo) { + private static void validate(@NetworkSource int networkSource, String ssid, + @SecurityType Set<Integer> securityTypes, + NetworkProviderInfo networkProviderInfo) { if (networkSource != NETWORK_SOURCE_UNKNOWN && networkSource != NETWORK_SOURCE_CLOUD_SELF && networkSource != NETWORK_SOURCE_NEARBY_SELF) { @@ -157,7 +163,7 @@ public final class KnownNetwork implements Parcelable { if (securityTypes.isEmpty()) { throw new IllegalArgumentException("SecurityTypes must be set"); } - if (networkSource == NETWORK_SOURCE_NEARBY_SELF && deviceInfo == null) { + if (networkSource == NETWORK_SOURCE_NEARBY_SELF && networkProviderInfo == null) { throw new IllegalArgumentException("Device info must be provided when network source" + " is NETWORK_SOURCE_NEARBY_SELF"); } @@ -167,12 +173,12 @@ public final class KnownNetwork implements Parcelable { @NetworkSource int networkSource, @NonNull String ssid, @NonNull @SecurityType ArraySet<Integer> securityTypes, - @Nullable DeviceInfo deviceInfo) { - validate(networkSource, ssid, securityTypes, deviceInfo); + @Nullable NetworkProviderInfo networkProviderInfo) { + validate(networkSource, ssid, securityTypes, networkProviderInfo); mNetworkSource = networkSource; mSsid = ssid; mSecurityTypes = new ArraySet<>(securityTypes); - mDeviceInfo = deviceInfo; + mNetworkProviderInfo = networkProviderInfo; } /** @@ -213,8 +219,8 @@ public final class KnownNetwork implements Parcelable { * network source is cloud or unknown. */ @Nullable - public DeviceInfo getDeviceInfo() { - return mDeviceInfo; + public NetworkProviderInfo getNetworkProviderInfo() { + return mNetworkProviderInfo; } @Override @@ -224,12 +230,12 @@ public final class KnownNetwork implements Parcelable { return mNetworkSource == other.getNetworkSource() && Objects.equals(mSsid, other.getSsid()) && Objects.equals(mSecurityTypes, other.getSecurityTypes()) - && Objects.equals(mDeviceInfo, other.getDeviceInfo()); + && Objects.equals(mNetworkProviderInfo, other.getNetworkProviderInfo()); } @Override public int hashCode() { - return Objects.hash(mNetworkSource, mSsid, mSecurityTypes, mDeviceInfo); + return Objects.hash(mNetworkSource, mSsid, mSecurityTypes, mNetworkProviderInfo); } @Override @@ -242,7 +248,7 @@ public final class KnownNetwork implements Parcelable { dest.writeInt(mNetworkSource); dest.writeString(mSsid); dest.writeArraySet(mSecurityTypes); - mDeviceInfo.writeToParcel(dest, flags); + mNetworkProviderInfo.writeToParcel(dest, flags); } /** @@ -254,7 +260,7 @@ public final class KnownNetwork implements Parcelable { public static KnownNetwork readFromParcel(@NonNull Parcel in) { return new KnownNetwork(in.readInt(), in.readString(), (ArraySet<Integer>) in.readArraySet(null), - DeviceInfo.readFromParcel(in)); + NetworkProviderInfo.readFromParcel(in)); } @NonNull @@ -276,7 +282,7 @@ public final class KnownNetwork implements Parcelable { .append("NetworkSource=").append(mNetworkSource) .append(", ssid=").append(mSsid) .append(", securityTypes=").append(mSecurityTypes.toString()) - .append(", deviceInfo=").append(mDeviceInfo.toString()) + .append(", networkProviderInfo=").append(mNetworkProviderInfo.toString()) .append("]").toString(); } } diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java index b2f04ff49195..6bd0a5ecd4c8 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java @@ -120,8 +120,16 @@ public final class KnownNetworkConnectionStatus implements Parcelable { } } + private static void validate(@ConnectionStatus int status) { + if (status != CONNECTION_STATUS_UNKNOWN && status != CONNECTION_STATUS_SAVED + && status != CONNECTION_STATUS_SAVE_FAILED) { + throw new IllegalArgumentException("Illegal connection status"); + } + } + private KnownNetworkConnectionStatus(@ConnectionStatus int status, KnownNetwork knownNetwork, Bundle extras) { + validate(status); mStatus = status; mKnownNetwork = knownNetwork; mExtras = extras; diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.aidl index 35d5c15a161b..f3cbbc2963a3 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.aidl +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.aidl @@ -16,4 +16,4 @@ package android.net.wifi.sharedconnectivity.app; -parcelable DeviceInfo;
\ No newline at end of file +parcelable NetworkProviderInfo;
\ No newline at end of file diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java index 52abf33bc761..ed4d699ad4de 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java @@ -36,7 +36,7 @@ import java.util.Objects; * @hide */ @SystemApi -public final class DeviceInfo implements Parcelable { +public final class NetworkProviderInfo implements Parcelable { /** * Device type providing connectivity is unknown. @@ -59,6 +59,16 @@ public final class DeviceInfo implements Parcelable { public static final int DEVICE_TYPE_LAPTOP = 3; /** + * Device providing connectivity is a watch. + */ + public static final int DEVICE_TYPE_WATCH = 4; + + /** + * Device providing connectivity is a watch. + */ + public static final int DEVICE_TYPE_AUTO = 5; + + /** * @hide */ @Retention(RetentionPolicy.SOURCE) @@ -66,18 +76,22 @@ public final class DeviceInfo implements Parcelable { DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_PHONE, DEVICE_TYPE_TABLET, - DEVICE_TYPE_LAPTOP + DEVICE_TYPE_LAPTOP, + DEVICE_TYPE_WATCH, + DEVICE_TYPE_AUTO }) - public @interface DeviceType {} + public @interface DeviceType { + } - @DeviceType private final int mDeviceType; + @DeviceType + private final int mDeviceType; private final String mDeviceName; private final String mModelName; private final int mBatteryPercentage; private final int mConnectionStrength; /** - * Builder class for {@link DeviceInfo}. + * Builder class for {@link NetworkProviderInfo}. */ public static final class Builder { private int mDeviceType; @@ -86,7 +100,12 @@ public final class DeviceInfo implements Parcelable { private int mBatteryPercentage; private int mConnectionStrength; - public Builder() {} + public Builder(@NonNull String deviceName, @NonNull String modelName) { + Objects.requireNonNull(deviceName); + Objects.requireNonNull(modelName); + mDeviceName = deviceName; + mModelName = modelName; + } /** * Sets the device type that provides connectivity. @@ -108,6 +127,7 @@ public final class DeviceInfo implements Parcelable { */ @NonNull public Builder setDeviceName(@NonNull String deviceName) { + Objects.requireNonNull(deviceName); mDeviceName = deviceName; return this; } @@ -120,6 +140,7 @@ public final class DeviceInfo implements Parcelable { */ @NonNull public Builder setModelName(@NonNull String modelName) { + Objects.requireNonNull(modelName); mModelName = modelName; return this; } @@ -149,29 +170,24 @@ public final class DeviceInfo implements Parcelable { } /** - * Builds the {@link DeviceInfo} object. + * Builds the {@link NetworkProviderInfo} object. * - * @return Returns the built {@link DeviceInfo} object. + * @return Returns the built {@link NetworkProviderInfo} object. */ @NonNull - public DeviceInfo build() { - return new DeviceInfo(mDeviceType, mDeviceName, mModelName, mBatteryPercentage, + public NetworkProviderInfo build() { + return new NetworkProviderInfo(mDeviceType, mDeviceName, mModelName, mBatteryPercentage, mConnectionStrength); } } - private static void validate(int deviceType, String deviceName, String modelName, + private static void validate(@DeviceType int deviceType, String deviceName, String modelName, int batteryPercentage, int connectionStrength) { if (deviceType != DEVICE_TYPE_UNKNOWN && deviceType != DEVICE_TYPE_PHONE - && deviceType != DEVICE_TYPE_TABLET && deviceType != DEVICE_TYPE_LAPTOP) { + && deviceType != DEVICE_TYPE_TABLET && deviceType != DEVICE_TYPE_LAPTOP + && deviceType != DEVICE_TYPE_WATCH && deviceType != DEVICE_TYPE_AUTO) { throw new IllegalArgumentException("Illegal device type"); } - if (Objects.isNull(deviceName)) { - throw new IllegalArgumentException("DeviceName must be set"); - } - if (Objects.isNull(modelName)) { - throw new IllegalArgumentException("ModelName must be set"); - } if (batteryPercentage < 0 || batteryPercentage > 100) { throw new IllegalArgumentException("BatteryPercentage must be in range 0-100"); } @@ -180,7 +196,7 @@ public final class DeviceInfo implements Parcelable { } } - private DeviceInfo(@DeviceType int deviceType, @NonNull String deviceName, + private NetworkProviderInfo(@DeviceType int deviceType, @NonNull String deviceName, @NonNull String modelName, int batteryPercentage, int connectionStrength) { validate(deviceType, deviceName, modelName, batteryPercentage, connectionStrength); mDeviceType = deviceType; @@ -242,8 +258,8 @@ public final class DeviceInfo implements Parcelable { @Override public boolean equals(Object obj) { - if (!(obj instanceof DeviceInfo)) return false; - DeviceInfo other = (DeviceInfo) obj; + if (!(obj instanceof NetworkProviderInfo)) return false; + NetworkProviderInfo other = (NetworkProviderInfo) obj; return mDeviceType == other.getDeviceType() && Objects.equals(mDeviceName, other.mDeviceName) && Objects.equals(mModelName, other.mModelName) @@ -256,6 +272,7 @@ public final class DeviceInfo implements Parcelable { return Objects.hash(mDeviceType, mDeviceName, mModelName, mBatteryPercentage, mConnectionStrength); } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mDeviceType); @@ -271,32 +288,32 @@ public final class DeviceInfo implements Parcelable { } /** - * Creates a {@link DeviceInfo} object from a parcel. + * Creates a {@link NetworkProviderInfo} object from a parcel. * * @hide */ @NonNull - public static DeviceInfo readFromParcel(@NonNull Parcel in) { - return new DeviceInfo(in.readInt(), in.readString(), in.readString(), in.readInt(), + public static NetworkProviderInfo readFromParcel(@NonNull Parcel in) { + return new NetworkProviderInfo(in.readInt(), in.readString(), in.readString(), in.readInt(), in.readInt()); } @NonNull - public static final Creator<DeviceInfo> CREATOR = new Creator<DeviceInfo>() { + public static final Creator<NetworkProviderInfo> CREATOR = new Creator<NetworkProviderInfo>() { @Override - public DeviceInfo createFromParcel(Parcel in) { + public NetworkProviderInfo createFromParcel(Parcel in) { return readFromParcel(in); } @Override - public DeviceInfo[] newArray(int size) { - return new DeviceInfo[size]; + public NetworkProviderInfo[] newArray(int size) { + return new NetworkProviderInfo[size]; } }; @Override public String toString() { - return new StringBuilder("DeviceInfo[") + return new StringBuilder("NetworkProviderInfo[") .append("deviceType=").append(mDeviceType) .append(", deviceName=").append(mDeviceName) .append(", modelName=").append(mModelName) diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java index d2b9be783bca..eb04df64d6d0 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java @@ -32,14 +32,16 @@ import java.util.List; public interface SharedConnectivityClientCallback { /** * This method is being called by {@link SharedConnectivityService} to notify of a change in the - * list of available Tether Networks. - * @param networks Updated Tether Network list. + * list of available Hotspot Networks. + * + * @param networks Updated Hotspot Network list. */ - void onTetherNetworksUpdated(@NonNull List<TetherNetwork> networks); + void onHotspotNetworksUpdated(@NonNull List<HotspotNetwork> networks); /** * This method is being called by {@link SharedConnectivityService} to notify of a change in the * list of available Known Networks. + * * @param networks Updated Known Network list. */ void onKnownNetworksUpdated(@NonNull List<KnownNetwork> networks); @@ -47,20 +49,23 @@ public interface SharedConnectivityClientCallback { /** * This method is being called by {@link SharedConnectivityService} to notify of a change in the * state of share connectivity settings. + * * @param state The new state. */ void onSharedConnectivitySettingsChanged(@NonNull SharedConnectivitySettingsState state); /** * This method is being called by {@link SharedConnectivityService} to notify of a change in the - * status of the current tether network connection. + * status of the current hotspot network connection. + * * @param status The new status. */ - void onTetherNetworkConnectionStatusChanged(@NonNull TetherNetworkConnectionStatus status); + void onHotspotNetworkConnectionStatusChanged(@NonNull HotspotNetworkConnectionStatus status); /** * This method is being called by {@link SharedConnectivityService} to notify of a change in the * status of the current known network connection. + * * @param status The new status. */ void onKnownNetworkConnectionStatusChanged(@NonNull KnownNetworkConnectionStatus status); diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java index c09f85b39ee4..684b385d60e8 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java @@ -49,7 +49,7 @@ import java.util.concurrent.Executor; * This class is the library used by consumers of Shared Connectivity data to bind to the service, * receive callbacks from, and send user actions to the service. * - * The methods {@link #connectTetherNetwork}, {@link #disconnectTetherNetwork}, + * The methods {@link #connectHotspotNetwork}, {@link #disconnectHotspotNetwork}, * {@link #connectKnownNetwork} and {@link #forgetKnownNetwork} are not valid and will return false * if not called between {@link SharedConnectivityClientCallback#onServiceConnected()} * and {@link SharedConnectivityClientCallback#onServiceDisconnected()} or if @@ -74,12 +74,11 @@ public class SharedConnectivityManager { mCallback = callback; } - @Override - public void onTetherNetworksUpdated(@NonNull List<TetherNetwork> networks) { + public void onHotspotNetworksUpdated(@NonNull List<HotspotNetwork> networks) { if (mCallback != null) { final long token = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> mCallback.onTetherNetworksUpdated(networks)); + mExecutor.execute(() -> mCallback.onHotspotNetworksUpdated(networks)); } finally { Binder.restoreCallingIdentity(token); } @@ -111,14 +110,13 @@ public class SharedConnectivityManager { } } - @Override - public void onTetherNetworkConnectionStatusChanged( - @NonNull TetherNetworkConnectionStatus status) { + public void onHotspotNetworkConnectionStatusChanged( + @NonNull HotspotNetworkConnectionStatus status) { if (mCallback != null) { final long token = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> - mCallback.onTetherNetworkConnectionStatusChanged(status)); + mCallback.onHotspotNetworkConnectionStatusChanged(status)); } finally { Binder.restoreCallingIdentity(token); } @@ -259,8 +257,8 @@ public class SharedConnectivityManager { } /** - * Registers a callback for receiving updates to the list of Tether Networks, Known Networks, - * shared connectivity settings state, tether network connection status and known network + * Registers a callback for receiving updates to the list of Hotspot Networks, Known Networks, + * shared connectivity settings state, hotspot network connection status and known network * connection status. * The {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} will be called if the * registration failed. @@ -331,26 +329,26 @@ public class SharedConnectivityManager { /** * Send command to the implementation of {@link SharedConnectivityService} requesting connection - * to the specified Tether Network. + * to the specified Hotspot Network. * - * @param network {@link TetherNetwork} object representing the network the user has requested + * @param network {@link HotspotNetwork} object representing the network the user has requested * a connection to. * @return Returns true if the service received the command. Does not guarantee that the - * connection was successful. + * connection was successful. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) - public boolean connectTetherNetwork(@NonNull TetherNetwork network) { - Objects.requireNonNull(network, "Tether network cannot be null"); + public boolean connectHotspotNetwork(@NonNull HotspotNetwork network) { + Objects.requireNonNull(network, "Hotspot network cannot be null"); if (mService == null) { return false; } try { - mService.connectTetherNetwork(network); + mService.connectHotspotNetwork(network); } catch (RemoteException e) { - Log.e(TAG, "Exception in connectTetherNetwork", e); + Log.e(TAG, "Exception in connectHotspotNetwork", e); return false; } return true; @@ -358,24 +356,24 @@ public class SharedConnectivityManager { /** * Send command to the implementation of {@link SharedConnectivityService} requesting - * disconnection from the active Tether Network. + * disconnection from the active Hotspot Network. * - * @param network {@link TetherNetwork} object representing the network the user has requested + * @param network {@link HotspotNetwork} object representing the network the user has requested * to disconnect from. * @return Returns true if the service received the command. Does not guarantee that the - * disconnection was successful. + * disconnection was successful. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) - public boolean disconnectTetherNetwork(@NonNull TetherNetwork network) { + public boolean disconnectHotspotNetwork(@NonNull HotspotNetwork network) { if (mService == null) { return false; } try { - mService.disconnectTetherNetwork(network); + mService.disconnectHotspotNetwork(network); } catch (RemoteException e) { - Log.e(TAG, "Exception in disconnectTetherNetwork", e); + Log.e(TAG, "Exception in disconnectHotspotNetwork", e); return false; } return true; @@ -388,7 +386,7 @@ public class SharedConnectivityManager { * @param network {@link KnownNetwork} object representing the network the user has requested * a connection to. * @return Returns true if the service received the command. Does not guarantee that the - * connection was successful. + * connection was successful. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @@ -413,7 +411,7 @@ public class SharedConnectivityManager { * the specified Known Network from the list of Known Networks. * * @return Returns true if the service received the command. Does not guarantee that the - * forget action was successful. + * forget action was successful. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @@ -434,22 +432,22 @@ public class SharedConnectivityManager { } /** - * Gets the list of tether networks the user can select to connect to. + * Gets the list of hotspot networks the user can select to connect to. * - * @return Returns a {@link List} of {@link TetherNetwork} objects, empty list on failure. + * @return Returns a {@link List} of {@link HotspotNetwork} objects, empty list on failure. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @NonNull - public List<TetherNetwork> getTetherNetworks() { + public List<HotspotNetwork> getHotspotNetworks() { if (mService == null) { return List.of(); } try { - return mService.getTetherNetworks(); + return mService.getHotspotNetworks(); } catch (RemoteException e) { - Log.e(TAG, "Exception in getTetherNetworks", e); + Log.e(TAG, "Exception in getHotspotNetworks", e); } return List.of(); } @@ -498,24 +496,24 @@ public class SharedConnectivityManager { } /** - * Gets the connection status of the tether network the user selected to connect to. + * Gets the connection status of the hotspot network the user selected to connect to. * - * @return Returns a {@link TetherNetworkConnectionStatus} object with the connection status, + * @return Returns a {@link HotspotNetworkConnectionStatus} object with the connection status, * null on failure. If no connection is active the status will be - * {@link TetherNetworkConnectionStatus#CONNECTION_STATUS_UNKNOWN}. + * {@link HotspotNetworkConnectionStatus#CONNECTION_STATUS_UNKNOWN}. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @Nullable - public TetherNetworkConnectionStatus getTetherNetworkConnectionStatus() { + public HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus() { if (mService == null) { return null; } try { - return mService.getTetherNetworkConnectionStatus(); + return mService.getHotspotNetworkConnectionStatus(); } catch (RemoteException e) { - Log.e(TAG, "Exception in getTetherNetworkConnectionStatus", e); + Log.e(TAG, "Exception in getHotspotNetworkConnectionStatus", e); } return null; } diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl index 6f6f1627c6a5..737aa6d9964c 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl @@ -19,15 +19,15 @@ package android.net.wifi.sharedconnectivity.service; import android.net.wifi.sharedconnectivity.app.KnownNetwork; import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus; import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState; -import android.net.wifi.sharedconnectivity.app.TetherNetwork; -import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus; +import android.net.wifi.sharedconnectivity.app.HotspotNetwork; +import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus; /* * @hide */ interface ISharedConnectivityCallback { - oneway void onTetherNetworksUpdated(in List<TetherNetwork> networks); - oneway void onTetherNetworkConnectionStatusChanged(in TetherNetworkConnectionStatus status); + oneway void onHotspotNetworksUpdated(in List<HotspotNetwork> networks); + oneway void onHotspotNetworkConnectionStatusChanged(in HotspotNetworkConnectionStatus status); oneway void onKnownNetworksUpdated(in List<KnownNetwork> networks); oneway void onKnownNetworkConnectionStatusChanged(in KnownNetworkConnectionStatus status); oneway void onSharedConnectivitySettingsChanged(in SharedConnectivitySettingsState state); diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl index 9f33e99ad3d1..c81380df3c79 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl @@ -17,10 +17,10 @@ package android.net.wifi.sharedconnectivity.service; import android.net.wifi.sharedconnectivity.app.KnownNetwork; -import android.net.wifi.sharedconnectivity.app.TetherNetwork; +import android.net.wifi.sharedconnectivity.app.HotspotNetwork; import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus; import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState; -import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus; +import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus; import android.net.wifi.sharedconnectivity.service.ISharedConnectivityCallback; /* @@ -29,13 +29,13 @@ import android.net.wifi.sharedconnectivity.service.ISharedConnectivityCallback; interface ISharedConnectivityService { void registerCallback(in ISharedConnectivityCallback callback); void unregisterCallback(in ISharedConnectivityCallback callback); - void connectTetherNetwork(in TetherNetwork network); - void disconnectTetherNetwork(in TetherNetwork network); + void connectHotspotNetwork(in HotspotNetwork network); + void disconnectHotspotNetwork(in HotspotNetwork network); void connectKnownNetwork(in KnownNetwork network); void forgetKnownNetwork(in KnownNetwork network); - List<TetherNetwork> getTetherNetworks(); + List<HotspotNetwork> getHotspotNetworks(); List<KnownNetwork> getKnownNetworks(); SharedConnectivitySettingsState getSettingsState(); - TetherNetworkConnectionStatus getTetherNetworkConnectionStatus(); + HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus(); KnownNetworkConnectionStatus getKnownNetworkConnectionStatus(); } diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java index 4c88c1b269a9..c53da9c15d4d 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java @@ -27,12 +27,12 @@ import android.annotation.TestApi; import android.app.Service; import android.content.Intent; import android.content.pm.PackageManager; +import android.net.wifi.sharedconnectivity.app.HotspotNetwork; +import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus; import android.net.wifi.sharedconnectivity.app.KnownNetwork; import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus; import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager; import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState; -import android.net.wifi.sharedconnectivity.app.TetherNetwork; -import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -62,14 +62,14 @@ public abstract class SharedConnectivityService extends Service { private Handler mHandler; private final RemoteCallbackList<ISharedConnectivityCallback> mRemoteCallbackList = new RemoteCallbackList<>(); - private List<TetherNetwork> mTetherNetworks = Collections.emptyList(); + private List<HotspotNetwork> mHotspotNetworks = Collections.emptyList(); private List<KnownNetwork> mKnownNetworks = Collections.emptyList(); private SharedConnectivitySettingsState mSettingsState = new SharedConnectivitySettingsState.Builder().setInstantTetherEnabled(false) .setExtras(Bundle.EMPTY).build(); - private TetherNetworkConnectionStatus mTetherNetworkConnectionStatus = - new TetherNetworkConnectionStatus.Builder() - .setStatus(TetherNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN) + private HotspotNetworkConnectionStatus mHotspotNetworkConnectionStatus = + new HotspotNetworkConnectionStatus.Builder() + .setStatus(HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN) .setExtras(Bundle.EMPTY).build(); private KnownNetworkConnectionStatus mKnownNetworkConnectionStatus = new KnownNetworkConnectionStatus.Builder() @@ -84,8 +84,8 @@ public abstract class SharedConnectivityService extends Service { IBinder serviceStub = new ISharedConnectivityService.Stub() { /** - * Registers a callback for receiving updates to the list of Tether Networks, Known - * Networks, shared connectivity settings state, tether network connection status and + * Registers a callback for receiving updates to the list of Hotspot Networks, Known + * Networks, shared connectivity settings state, hotspot network connection status and * known network connection status. * * @param callback The callback of type {@link ISharedConnectivityCallback} to be called @@ -113,29 +113,28 @@ public abstract class SharedConnectivityService extends Service { } /** - * Connects to a tether network. + * Connects to a hotspot network. * * @param network The network to connect to. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @Override - public void connectTetherNetwork(TetherNetwork network) { + public void connectHotspotNetwork(HotspotNetwork network) { checkPermissions(); - mHandler.post(() -> onConnectTetherNetwork(network)); + mHandler.post(() -> onConnectHotspotNetwork(network)); } /** - * Disconnects from a previously connected tether network. + * Disconnects from a previously connected hotspot network. * * @param network The network to disconnect from. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) - @Override - public void disconnectTetherNetwork(TetherNetwork network) { + public void disconnectHotspotNetwork(HotspotNetwork network) { checkPermissions(); - mHandler.post(() -> onDisconnectTetherNetwork(network)); + mHandler.post(() -> onDisconnectHotspotNetwork(network)); } /** @@ -164,16 +163,16 @@ public abstract class SharedConnectivityService extends Service { } /** - * Gets the list of tether networks the user can select to connect to. + * Gets the list of hotspot networks the user can select to connect to. * - * @return Returns a {@link List} of {@link TetherNetwork} objects + * @return Returns a {@link List} of {@link HotspotNetwork} objects */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @Override - public List<TetherNetwork> getTetherNetworks() { + public List<HotspotNetwork> getHotspotNetworks() { checkPermissions(); - return mTetherNetworks; + return mHotspotNetworks; } /** @@ -203,17 +202,17 @@ public abstract class SharedConnectivityService extends Service { } /** - * Gets the connection status of the tether network the user selected to connect to. + * Gets the connection status of the hotspot network the user selected to connect to. * - * @return Returns a {@link TetherNetworkConnectionStatus} object with the connection + * @return Returns a {@link HotspotNetworkConnectionStatus} object with the connection * status. */ @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) @Override - public TetherNetworkConnectionStatus getTetherNetworkConnectionStatus() { + public HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus() { checkPermissions(); - return mTetherNetworkConnectionStatus; + return mHotspotNetworkConnectionStatus; } /** @@ -254,7 +253,8 @@ public abstract class SharedConnectivityService extends Service { /** @hide */ @TestApi - public void onBind() {} + public void onBind() { + } private void onRegisterCallback(ISharedConnectivityCallback callback) { mRemoteCallbackList.register(callback); @@ -265,23 +265,23 @@ public abstract class SharedConnectivityService extends Service { } /** - * Implementing application should call this method to provide an up-to-date list of Tether + * Implementing application should call this method to provide an up-to-date list of Hotspot * Networks to be displayed to the user. * * This method updates the cached list and notifies all registered callbacks. Any callbacks that * are inaccessible will be unregistered. * - * @param networks The updated list of {@link TetherNetwork} objects. + * @param networks The updated list of {@link HotspotNetwork} objects. */ - public final void setTetherNetworks(@NonNull List<TetherNetwork> networks) { - mTetherNetworks = networks; + public final void setHotspotNetworks(@NonNull List<HotspotNetwork> networks) { + mHotspotNetworks = networks; int count = mRemoteCallbackList.beginBroadcast(); for (int i = 0; i < count; i++) { try { - mRemoteCallbackList.getBroadcastItem(i).onTetherNetworksUpdated(mTetherNetworks); + mRemoteCallbackList.getBroadcastItem(i).onHotspotNetworksUpdated(mHotspotNetworks); } catch (RemoteException e) { - if (DEBUG) Log.w(TAG, "Exception in setTetherNetworks", e); + if (DEBUG) Log.w(TAG, "Exception in setHotspotNetworks", e); } } mRemoteCallbackList.finishBroadcast(); @@ -318,7 +318,7 @@ public abstract class SharedConnectivityService extends Service { * that are inaccessible will be unregistered. * * @param settingsState The updated state {@link SharedConnectivitySettingsState} - * objects. + * objects. */ public final void setSettingsState(@NonNull SharedConnectivitySettingsState settingsState) { mSettingsState = settingsState; @@ -337,23 +337,22 @@ public abstract class SharedConnectivityService extends Service { /** * Implementing application should call this method to provide an up-to-date status of enabling - * and connecting to the tether network. - * - * @param status The updated status {@link TetherNetworkConnectionStatus} of the connection. + * and connecting to the hotspot network. * + * @param status The updated status {@link HotspotNetworkConnectionStatus} of the connection. */ - public final void updateTetherNetworkConnectionStatus( - @NonNull TetherNetworkConnectionStatus status) { - mTetherNetworkConnectionStatus = status; + public final void updateHotspotNetworkConnectionStatus( + @NonNull HotspotNetworkConnectionStatus status) { + mHotspotNetworkConnectionStatus = status; int count = mRemoteCallbackList.beginBroadcast(); for (int i = 0; i < count; i++) { try { mRemoteCallbackList - .getBroadcastItem(i).onTetherNetworkConnectionStatusChanged( - mTetherNetworkConnectionStatus); + .getBroadcastItem(i).onHotspotNetworkConnectionStatusChanged( + mHotspotNetworkConnectionStatus); } catch (RemoteException e) { - if (DEBUG) Log.w(TAG, "Exception in updateTetherNetworkConnectionStatus", e); + if (DEBUG) Log.w(TAG, "Exception in updateHotspotNetworkConnectionStatus", e); } } mRemoteCallbackList.finishBroadcast(); @@ -364,7 +363,6 @@ public abstract class SharedConnectivityService extends Service { * connecting to a known network. * * @param status The updated status {@link KnownNetworkConnectionStatus} of the connection. - * */ public final void updateKnownNetworkConnectionStatus( @NonNull KnownNetworkConnectionStatus status) { @@ -386,20 +384,20 @@ public abstract class SharedConnectivityService extends Service { /** * Implementing application should implement this method. * - * Implementation should initiate a connection to the Tether Network indicated. + * Implementation should initiate a connection to the Hotspot Network indicated. * - * @param network Object identifying the Tether Network the user has requested a connection to. + * @param network Object identifying the Hotspot Network the user has requested a connection to. */ - public abstract void onConnectTetherNetwork(@NonNull TetherNetwork network); + public abstract void onConnectHotspotNetwork(@NonNull HotspotNetwork network); /** * Implementing application should implement this method. * - * Implementation should initiate a disconnection from the active Tether Network. + * Implementation should initiate a disconnection from the active Hotspot Network. * - * @param network Object identifying the Tether Network the user has requested to disconnect. + * @param network Object identifying the Hotspot Network the user has requested to disconnect. */ - public abstract void onDisconnectTetherNetwork(@NonNull TetherNetwork network); + public abstract void onDisconnectHotspotNetwork(@NonNull HotspotNetwork network); /** * Implementing application should implement this method. diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatusTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatusTest.java index 0844364e7a63..b18ab5060924 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatusTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatusTest.java @@ -18,10 +18,10 @@ package android.net.wifi.sharedconnectivity.app; import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP; import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET; -import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR; -import static android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT; -import static android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT; +import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR; +import static android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT; +import static android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET; import static com.google.common.truth.Truth.assertThat; @@ -35,14 +35,15 @@ import org.junit.Test; import java.util.Arrays; /** - * Unit tests for {@link TetherNetworkConnectionStatus}. + * Unit tests for {@link HotspotNetworkConnectionStatus}. */ @SmallTest -public class TetherNetworkConnectionStatusTest { +public class HotspotNetworkConnectionStatusTest { private static final long DEVICE_ID = 11L; - private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2) + .setBatteryPercentage(50).build(); private static final int NETWORK_TYPE = NETWORK_TYPE_CELLULAR; private static final String NETWORK_NAME = "TEST_NETWORK"; private static final String HOTSPOT_SSID = "TEST_SSID"; @@ -57,7 +58,7 @@ public class TetherNetworkConnectionStatusTest { */ @Test public void testParcelOperation() { - TetherNetworkConnectionStatus status = buildConnectionStatusBuilder().build(); + HotspotNetworkConnectionStatus status = buildConnectionStatusBuilder().build(); Parcel parcelW = Parcel.obtain(); status.writeToParcel(parcelW, 0); @@ -67,8 +68,8 @@ public class TetherNetworkConnectionStatusTest { Parcel parcelR = Parcel.obtain(); parcelR.unmarshall(bytes, 0, bytes.length); parcelR.setDataPosition(0); - TetherNetworkConnectionStatus fromParcel = - TetherNetworkConnectionStatus.CREATOR.createFromParcel(parcelR); + HotspotNetworkConnectionStatus fromParcel = + HotspotNetworkConnectionStatus.CREATOR.createFromParcel(parcelR); assertThat(fromParcel).isEqualTo(status); assertThat(fromParcel.hashCode()).isEqualTo(status.hashCode()); @@ -79,16 +80,16 @@ public class TetherNetworkConnectionStatusTest { */ @Test public void testEqualsOperation() { - TetherNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build(); - TetherNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build(); + HotspotNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build(); + HotspotNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build(); assertThat(status1).isEqualTo(status2); - TetherNetworkConnectionStatus.Builder builder = buildConnectionStatusBuilder() + HotspotNetworkConnectionStatus.Builder builder = buildConnectionStatusBuilder() .setStatus(CONNECTION_STATUS_TETHERING_TIMEOUT); assertThat(builder.build()).isNotEqualTo(status1); builder = buildConnectionStatusBuilder() - .setTetherNetwork(buildTetherNetworkBuilder().setDeviceId(DEVICE_ID_1).build()); + .setHotspotNetwork(buildHotspotNetworkBuilder().setDeviceId(DEVICE_ID_1).build()); assertThat(builder.build()).isNotEqualTo(status1); } @@ -97,24 +98,24 @@ public class TetherNetworkConnectionStatusTest { */ @Test public void testGetMethods() { - TetherNetworkConnectionStatus status = buildConnectionStatusBuilder().build(); + HotspotNetworkConnectionStatus status = buildConnectionStatusBuilder().build(); assertThat(status.getStatus()).isEqualTo(CONNECTION_STATUS_ENABLING_HOTSPOT); - assertThat(status.getTetherNetwork()).isEqualTo(buildTetherNetworkBuilder().build()); + assertThat(status.getHotspotNetwork()).isEqualTo(buildHotspotNetworkBuilder().build()); assertThat(status.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE); } @Test public void testHashCode() { - TetherNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build(); - TetherNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build(); + HotspotNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build(); + HotspotNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build(); assertThat(status1.hashCode()).isEqualTo(status2.hashCode()); } - private TetherNetworkConnectionStatus.Builder buildConnectionStatusBuilder() { - return new TetherNetworkConnectionStatus.Builder() + private HotspotNetworkConnectionStatus.Builder buildConnectionStatusBuilder() { + return new HotspotNetworkConnectionStatus.Builder() .setStatus(CONNECTION_STATUS_ENABLING_HOTSPOT) - .setTetherNetwork(buildTetherNetworkBuilder().build()) + .setHotspotNetwork(buildHotspotNetworkBuilder().build()) .setExtras(buildBundle()); } @@ -124,11 +125,11 @@ public class TetherNetworkConnectionStatusTest { return bundle; } - private TetherNetwork.Builder buildTetherNetworkBuilder() { - TetherNetwork.Builder builder = new TetherNetwork.Builder() + private HotspotNetwork.Builder buildHotspotNetworkBuilder() { + HotspotNetwork.Builder builder = new HotspotNetwork.Builder() .setDeviceId(DEVICE_ID) - .setDeviceInfo(DEVICE_INFO) - .setNetworkType(NETWORK_TYPE) + .setNetworkProviderInfo(NETWORK_PROVIDER_INFO) + .setHostNetworkType(NETWORK_TYPE) .setNetworkName(NETWORK_NAME) .setHotspotSsid(HOTSPOT_SSID) .setHotspotBssid(HOTSPOT_BSSID); diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java index a50d76782c4a..8e396b68ad3a 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java @@ -19,10 +19,10 @@ package android.net.wifi.sharedconnectivity.app; import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP; import static android.net.wifi.WifiInfo.SECURITY_TYPE_PSK; import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_PHONE; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET; -import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR; -import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_WIFI; +import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR; +import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_WIFI; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_PHONE; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET; import static com.google.common.truth.Truth.assertThat; @@ -36,14 +36,15 @@ import org.junit.Test; import java.util.Arrays; /** - * Unit tests for {@link TetherNetwork}. + * Unit tests for {@link HotspotNetwork}. */ @SmallTest -public class TetherNetworkTest { +public class HotspotNetworkTest { private static final long DEVICE_ID = 11L; - private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2) + .setBatteryPercentage(50).build(); private static final int NETWORK_TYPE = NETWORK_TYPE_CELLULAR; private static final String NETWORK_NAME = "TEST_NETWORK"; private static final String HOTSPOT_SSID = "TEST_SSID"; @@ -51,9 +52,10 @@ public class TetherNetworkTest { private static final int[] HOTSPOT_SECURITY_TYPES = {SECURITY_TYPE_WEP, SECURITY_TYPE_EAP}; private static final long DEVICE_ID_1 = 111L; - private static final DeviceInfo DEVICE_INFO_1 = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_PHONE).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO1 = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_PHONE).setConnectionStrength(2) + .setBatteryPercentage(50).build(); private static final int NETWORK_TYPE_1 = NETWORK_TYPE_WIFI; private static final String NETWORK_NAME_1 = "TEST_NETWORK1"; private static final String HOTSPOT_SSID_1 = "TEST_SSID1"; @@ -65,7 +67,7 @@ public class TetherNetworkTest { */ @Test public void testParcelOperation() { - TetherNetwork network = buildTetherNetworkBuilder().build(); + HotspotNetwork network = buildHotspotNetworkBuilder().build(); Parcel parcelW = Parcel.obtain(); network.writeToParcel(parcelW, 0); @@ -75,7 +77,7 @@ public class TetherNetworkTest { Parcel parcelR = Parcel.obtain(); parcelR.unmarshall(bytes, 0, bytes.length); parcelR.setDataPosition(0); - TetherNetwork fromParcel = TetherNetwork.CREATOR.createFromParcel(parcelR); + HotspotNetwork fromParcel = HotspotNetwork.CREATOR.createFromParcel(parcelR); assertThat(fromParcel).isEqualTo(network); assertThat(fromParcel.hashCode()).isEqualTo(network.hashCode()); @@ -86,30 +88,30 @@ public class TetherNetworkTest { */ @Test public void testEqualsOperation() { - TetherNetwork network1 = buildTetherNetworkBuilder().build(); - TetherNetwork network2 = buildTetherNetworkBuilder().build(); + HotspotNetwork network1 = buildHotspotNetworkBuilder().build(); + HotspotNetwork network2 = buildHotspotNetworkBuilder().build(); assertThat(network1).isEqualTo(network2); - TetherNetwork.Builder builder = buildTetherNetworkBuilder().setDeviceId(DEVICE_ID_1); + HotspotNetwork.Builder builder = buildHotspotNetworkBuilder().setDeviceId(DEVICE_ID_1); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildTetherNetworkBuilder().setDeviceInfo(DEVICE_INFO_1); + builder = buildHotspotNetworkBuilder().setNetworkProviderInfo(NETWORK_PROVIDER_INFO1); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildTetherNetworkBuilder().setNetworkType(NETWORK_TYPE_1); + builder = buildHotspotNetworkBuilder().setHostNetworkType(NETWORK_TYPE_1); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildTetherNetworkBuilder().setNetworkName(NETWORK_NAME_1); + builder = buildHotspotNetworkBuilder().setNetworkName(NETWORK_NAME_1); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildTetherNetworkBuilder().setHotspotSsid(HOTSPOT_SSID_1); + builder = buildHotspotNetworkBuilder().setHotspotSsid(HOTSPOT_SSID_1); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildTetherNetworkBuilder().setHotspotBssid(HOTSPOT_BSSID_1); + builder = buildHotspotNetworkBuilder().setHotspotBssid(HOTSPOT_BSSID_1); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildTetherNetworkBuilder(); - TetherNetwork.Builder builder1 = buildTetherNetworkBuilder(); + builder = buildHotspotNetworkBuilder(); + HotspotNetwork.Builder builder1 = buildHotspotNetworkBuilder(); Arrays.stream(HOTSPOT_SECURITY_TYPES_1).forEach(builder1::addHotspotSecurityType); assertThat(builder1.build()).isNotEqualTo(builder.build()); @@ -120,13 +122,13 @@ public class TetherNetworkTest { */ @Test public void testGetMethods() { - TetherNetwork network = buildTetherNetworkBuilder().build(); + HotspotNetwork network = buildHotspotNetworkBuilder().build(); ArraySet<Integer> securityTypes = new ArraySet<>(); Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(securityTypes::add); assertThat(network.getDeviceId()).isEqualTo(DEVICE_ID); - assertThat(network.getDeviceInfo()).isEqualTo(DEVICE_INFO); - assertThat(network.getNetworkType()).isEqualTo(NETWORK_TYPE); + assertThat(network.getNetworkProviderInfo()).isEqualTo(NETWORK_PROVIDER_INFO); + assertThat(network.getHostNetworkType()).isEqualTo(NETWORK_TYPE); assertThat(network.getNetworkName()).isEqualTo(NETWORK_NAME); assertThat(network.getHotspotSsid()).isEqualTo(HOTSPOT_SSID); assertThat(network.getHotspotBssid()).isEqualTo(HOTSPOT_BSSID); @@ -135,17 +137,17 @@ public class TetherNetworkTest { @Test public void testHashCode() { - TetherNetwork network1 = buildTetherNetworkBuilder().build(); - TetherNetwork network2 = buildTetherNetworkBuilder().build(); + HotspotNetwork network1 = buildHotspotNetworkBuilder().build(); + HotspotNetwork network2 = buildHotspotNetworkBuilder().build(); assertThat(network1.hashCode()).isEqualTo(network2.hashCode()); } - private TetherNetwork.Builder buildTetherNetworkBuilder() { - TetherNetwork.Builder builder = new TetherNetwork.Builder() + private HotspotNetwork.Builder buildHotspotNetworkBuilder() { + HotspotNetwork.Builder builder = new HotspotNetwork.Builder() .setDeviceId(DEVICE_ID) - .setDeviceInfo(DEVICE_INFO) - .setNetworkType(NETWORK_TYPE) + .setNetworkProviderInfo(NETWORK_PROVIDER_INFO) + .setHostNetworkType(NETWORK_TYPE) .setNetworkName(NETWORK_NAME) .setHotspotSsid(HOTSPOT_SSID) .setHotspotBssid(HOTSPOT_BSSID); diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java index 8a0f21e5eea6..f98a0fcc7574 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java @@ -17,10 +17,10 @@ package android.net.wifi.sharedconnectivity.app; import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET; import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF; import static android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.CONNECTION_STATUS_SAVED; import static android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.CONNECTION_STATUS_SAVE_FAILED; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET; import static com.google.common.truth.Truth.assertThat; @@ -41,9 +41,10 @@ public class KnownNetworkConnectionStatusTest { private static final int NETWORK_SOURCE = NETWORK_SOURCE_NEARBY_SELF; private static final String SSID = "TEST_SSID"; private static final int[] SECURITY_TYPES = {SECURITY_TYPE_WEP}; - private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2) + .setBatteryPercentage(50).build(); private static final String SSID_1 = "TEST_SSID1"; private static final String BUNDLE_KEY = "INT-KEY"; private static final int BUNDLE_VALUE = 1; @@ -121,8 +122,8 @@ public class KnownNetworkConnectionStatusTest { } private KnownNetwork.Builder buildKnownNetworkBuilder() { - KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE) - .setSsid(SSID).setDeviceInfo(DEVICE_INFO); + KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE) + .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO); Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType); return builder; } diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java index 872dd2e63227..1ecba7644cf9 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java @@ -18,10 +18,10 @@ package android.net.wifi.sharedconnectivity.app; import static android.net.wifi.WifiInfo.SECURITY_TYPE_PSK; import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_PHONE; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET; import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_CLOUD_SELF; import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_PHONE; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET; import static com.google.common.truth.Truth.assertThat; @@ -43,15 +43,17 @@ public class KnownNetworkTest { private static final int NETWORK_SOURCE = NETWORK_SOURCE_NEARBY_SELF; private static final String SSID = "TEST_SSID"; private static final int[] SECURITY_TYPES = {SECURITY_TYPE_WEP}; - private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2) + .setBatteryPercentage(50).build(); private static final int NETWORK_SOURCE_1 = NETWORK_SOURCE_CLOUD_SELF; private static final String SSID_1 = "TEST_SSID1"; private static final int[] SECURITY_TYPES_1 = {SECURITY_TYPE_PSK}; - private static final DeviceInfo DEVICE_INFO_1 = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_PHONE).setDeviceName("TEST_NAME_1") - .setModelName("TEST_MODEL_1").setConnectionStrength(3).setBatteryPercentage(33).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO1 = + new NetworkProviderInfo.Builder("TEST_NAME_1", "TEST_MODEL_1") + .setDeviceType(DEVICE_TYPE_PHONE).setConnectionStrength(3) + .setBatteryPercentage(33).build(); /** * Verifies parcel serialization/deserialization. @@ -94,7 +96,7 @@ public class KnownNetworkTest { Arrays.stream(SECURITY_TYPES_1).forEach(builder::addSecurityType); assertThat(builder.build()).isNotEqualTo(network1); - builder = buildKnownNetworkBuilder().setDeviceInfo(DEVICE_INFO_1); + builder = buildKnownNetworkBuilder().setNetworkProviderInfo(NETWORK_PROVIDER_INFO1); assertThat(builder.build()).isNotEqualTo(network1); } @@ -110,7 +112,7 @@ public class KnownNetworkTest { assertThat(network.getNetworkSource()).isEqualTo(NETWORK_SOURCE); assertThat(network.getSsid()).isEqualTo(SSID); assertThat(network.getSecurityTypes()).containsExactlyElementsIn(securityTypes); - assertThat(network.getDeviceInfo()).isEqualTo(DEVICE_INFO); + assertThat(network.getNetworkProviderInfo()).isEqualTo(NETWORK_PROVIDER_INFO); } @Test @@ -122,8 +124,8 @@ public class KnownNetworkTest { } private KnownNetwork.Builder buildKnownNetworkBuilder() { - KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE) - .setSsid(SSID).setDeviceInfo(DEVICE_INFO); + KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE) + .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO); Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType); return builder; } diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/DeviceInfoTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java index e6595eb2e2a3..8f35d8d94a8b 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/DeviceInfoTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java @@ -16,8 +16,8 @@ package android.net.wifi.sharedconnectivity.app; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_LAPTOP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_PHONE; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_LAPTOP; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_PHONE; import static com.google.common.truth.Truth.assertThat; @@ -28,10 +28,10 @@ import androidx.test.filters.SmallTest; import org.junit.Test; /** - * Unit tests for {@link DeviceInfo}. + * Unit tests for {@link NetworkProviderInfo}. */ @SmallTest -public class DeviceInfoTest { +public class NetworkProviderInfoTest { private static final int DEVICE_TYPE = DEVICE_TYPE_PHONE; private static final String DEVICE_NAME = "TEST_NAME"; @@ -50,7 +50,7 @@ public class DeviceInfoTest { */ @Test public void testParcelOperation() { - DeviceInfo info = buildDeviceInfoBuilder().build(); + NetworkProviderInfo info = buildNetworkProviderInfoBuilder().build(); Parcel parcelW = Parcel.obtain(); info.writeToParcel(parcelW, 0); @@ -60,7 +60,7 @@ public class DeviceInfoTest { Parcel parcelR = Parcel.obtain(); parcelR.unmarshall(bytes, 0, bytes.length); parcelR.setDataPosition(0); - DeviceInfo fromParcel = DeviceInfo.CREATOR.createFromParcel(parcelR); + NetworkProviderInfo fromParcel = NetworkProviderInfo.CREATOR.createFromParcel(parcelR); assertThat(fromParcel).isEqualTo(info); assertThat(fromParcel.hashCode()).isEqualTo(info.hashCode()); @@ -71,24 +71,25 @@ public class DeviceInfoTest { */ @Test public void testEqualsOperation() { - DeviceInfo info1 = buildDeviceInfoBuilder().build(); - DeviceInfo info2 = buildDeviceInfoBuilder().build(); + NetworkProviderInfo info1 = buildNetworkProviderInfoBuilder().build(); + NetworkProviderInfo info2 = buildNetworkProviderInfoBuilder().build(); assertThat(info1).isEqualTo(info2); - DeviceInfo.Builder builder = buildDeviceInfoBuilder().setDeviceType(DEVICE_TYPE_1); + NetworkProviderInfo.Builder builder = buildNetworkProviderInfoBuilder().setDeviceType( + DEVICE_TYPE_1); assertThat(builder.build()).isNotEqualTo(info1); - builder = buildDeviceInfoBuilder().setDeviceName(DEVICE_NAME_1); + builder = buildNetworkProviderInfoBuilder().setDeviceName(DEVICE_NAME_1); assertThat(builder.build()).isNotEqualTo(info1); - builder = buildDeviceInfoBuilder().setModelName(DEVICE_MODEL_1); + builder = buildNetworkProviderInfoBuilder().setModelName(DEVICE_MODEL_1); assertThat(builder.build()).isNotEqualTo(info1); - builder = buildDeviceInfoBuilder() + builder = buildNetworkProviderInfoBuilder() .setBatteryPercentage(BATTERY_PERCENTAGE_1); assertThat(builder.build()).isNotEqualTo(info1); - builder = buildDeviceInfoBuilder() + builder = buildNetworkProviderInfoBuilder() .setConnectionStrength(CONNECTION_STRENGTH_1); assertThat(builder.build()).isNotEqualTo(info1); } @@ -98,7 +99,7 @@ public class DeviceInfoTest { */ @Test public void testGetMethods() { - DeviceInfo info = buildDeviceInfoBuilder().build(); + NetworkProviderInfo info = buildNetworkProviderInfoBuilder().build(); assertThat(info.getDeviceType()).isEqualTo(DEVICE_TYPE); assertThat(info.getDeviceName()).isEqualTo(DEVICE_NAME); assertThat(info.getModelName()).isEqualTo(DEVICE_MODEL); @@ -108,15 +109,15 @@ public class DeviceInfoTest { @Test public void testHashCode() { - DeviceInfo info1 = buildDeviceInfoBuilder().build(); - DeviceInfo info2 = buildDeviceInfoBuilder().build(); + NetworkProviderInfo info1 = buildNetworkProviderInfoBuilder().build(); + NetworkProviderInfo info2 = buildNetworkProviderInfoBuilder().build(); assertThat(info1.hashCode()).isEqualTo(info2.hashCode()); } - private DeviceInfo.Builder buildDeviceInfoBuilder() { - return new DeviceInfo.Builder().setDeviceType(DEVICE_TYPE).setDeviceName(DEVICE_NAME) - .setModelName(DEVICE_MODEL).setBatteryPercentage(BATTERY_PERCENTAGE) + private NetworkProviderInfo.Builder buildNetworkProviderInfoBuilder() { + return new NetworkProviderInfo.Builder(DEVICE_NAME, DEVICE_MODEL).setDeviceType(DEVICE_TYPE) + .setBatteryPercentage(BATTERY_PERCENTAGE) .setConnectionStrength(CONNECTION_STRENGTH); } } diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java index 7c0a8b65813c..8c573e302213 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java @@ -18,9 +18,9 @@ package android.net.wifi.sharedconnectivity.app; import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP; import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET; +import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR; import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF; -import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET; import static com.google.common.truth.Truth.assertThat; @@ -56,9 +56,10 @@ import java.util.concurrent.Executor; @SmallTest public class SharedConnectivityManagerTest { private static final long DEVICE_ID = 11L; - private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2) + .setBatteryPercentage(50).build(); private static final int NETWORK_TYPE = NETWORK_TYPE_CELLULAR; private static final String NETWORK_NAME = "TEST_NETWORK"; private static final String HOTSPOT_SSID = "TEST_SSID"; @@ -72,13 +73,16 @@ public class SharedConnectivityManagerTest { private static final String SERVICE_INTENT_ACTION = "TEST_INTENT_ACTION"; - @Mock Context mContext; + @Mock + Context mContext; @Mock ISharedConnectivityService mService; - @Mock Executor mExecutor; + @Mock + Executor mExecutor; @Mock SharedConnectivityClientCallback mClientCallback; - @Mock Resources mResources; + @Mock + Resources mResources; @Mock ISharedConnectivityService.Stub mIBinder; @@ -284,69 +288,69 @@ public class SharedConnectivityManagerTest { } /** - * Verifies connectTetherNetwork behavior. + * Verifies connectHotspotNetwork behavior. */ @Test - public void connectTetherNetwork_serviceNotConnected_shouldFail() { - TetherNetwork network = buildTetherNetwork(); + public void connectHotspotNetwork_serviceNotConnected_shouldFail() { + HotspotNetwork network = buildHotspotNetwork(); SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(null); - assertThat(manager.connectTetherNetwork(network)).isFalse(); + assertThat(manager.connectHotspotNetwork(network)).isFalse(); } @Test - public void connectTetherNetwork() throws RemoteException { - TetherNetwork network = buildTetherNetwork(); + public void connectHotspotNetwork() throws RemoteException { + HotspotNetwork network = buildHotspotNetwork(); SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(mService); - manager.connectTetherNetwork(network); + manager.connectHotspotNetwork(network); - verify(mService).connectTetherNetwork(network); + verify(mService).connectHotspotNetwork(network); } @Test - public void connectTetherNetwork_remoteException_shouldFail() throws RemoteException { - TetherNetwork network = buildTetherNetwork(); + public void connectHotspotNetwork_remoteException_shouldFail() throws RemoteException { + HotspotNetwork network = buildHotspotNetwork(); SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(mService); - doThrow(new RemoteException()).when(mService).connectTetherNetwork(network); + doThrow(new RemoteException()).when(mService).connectHotspotNetwork(network); - assertThat(manager.connectTetherNetwork(network)).isFalse(); + assertThat(manager.connectHotspotNetwork(network)).isFalse(); } /** - * Verifies disconnectTetherNetwork behavior. + * Verifies disconnectHotspotNetwork behavior. */ @Test - public void disconnectTetherNetwork_serviceNotConnected_shouldFail() { - TetherNetwork network = buildTetherNetwork(); + public void disconnectHotspotNetwork_serviceNotConnected_shouldFail() { + HotspotNetwork network = buildHotspotNetwork(); SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(null); - assertThat(manager.disconnectTetherNetwork(network)).isFalse(); + assertThat(manager.disconnectHotspotNetwork(network)).isFalse(); } @Test - public void disconnectTetherNetwork() throws RemoteException { - TetherNetwork network = buildTetherNetwork(); + public void disconnectHotspotNetwork() throws RemoteException { + HotspotNetwork network = buildHotspotNetwork(); SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(mService); - manager.disconnectTetherNetwork(network); + manager.disconnectHotspotNetwork(network); - verify(mService).disconnectTetherNetwork(network); + verify(mService).disconnectHotspotNetwork(network); } @Test - public void disconnectTetherNetwork_remoteException_shouldFail() throws RemoteException { - TetherNetwork network = buildTetherNetwork(); + public void disconnectHotspotNetwork_remoteException_shouldFail() throws RemoteException { + HotspotNetwork network = buildHotspotNetwork(); SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(mService); - doThrow(new RemoteException()).when(mService).disconnectTetherNetwork(any()); + doThrow(new RemoteException()).when(mService).disconnectHotspotNetwork(any()); - assertThat(manager.disconnectTetherNetwork(network)).isFalse(); + assertThat(manager.disconnectHotspotNetwork(network)).isFalse(); } /** @@ -419,7 +423,7 @@ public class SharedConnectivityManagerTest { * Verify getters. */ @Test - public void getTetherNetworks_serviceNotConnected_shouldReturnEmptyList() { + public void getHotspotNetworks_serviceNotConnected_shouldReturnEmptyList() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(null); @@ -427,22 +431,22 @@ public class SharedConnectivityManagerTest { } @Test - public void getTetherNetworks_remoteException_shouldReturnEmptyList() throws RemoteException { + public void getHotspotNetworks_remoteException_shouldReturnEmptyList() throws RemoteException { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(mService); - doThrow(new RemoteException()).when(mService).getTetherNetworks(); + doThrow(new RemoteException()).when(mService).getHotspotNetworks(); assertThat(manager.getKnownNetworks()).isEmpty(); } @Test - public void getTetherNetworks_shouldReturnNetworksList() throws RemoteException { + public void getHotspotNetworks_shouldReturnNetworksList() throws RemoteException { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); - List<TetherNetwork> networks = List.of(buildTetherNetwork()); + List<HotspotNetwork> networks = List.of(buildHotspotNetwork()); manager.setService(mService); - when(mService.getTetherNetworks()).thenReturn(networks); + when(mService.getHotspotNetworks()).thenReturn(networks); - assertThat(manager.getTetherNetworks()).containsExactly(buildTetherNetwork()); + assertThat(manager.getHotspotNetworks()).containsExactly(buildHotspotNetwork()); } @Test @@ -502,35 +506,35 @@ public class SharedConnectivityManagerTest { } @Test - public void getTetherNetworkConnectionStatus_serviceNotConnected_shouldReturnNull() + public void getHotspotNetworkConnectionStatus_serviceNotConnected_shouldReturnNull() throws RemoteException { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(null); - assertThat(manager.getTetherNetworkConnectionStatus()).isNull(); + assertThat(manager.getHotspotNetworkConnectionStatus()).isNull(); } @Test - public void getTetherNetworkConnectionStatus_remoteException_shouldReturnNull() + public void getHotspotNetworkConnectionStatus_remoteException_shouldReturnNull() throws RemoteException { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.setService(mService); - doThrow(new RemoteException()).when(mService).getTetherNetworkConnectionStatus(); + doThrow(new RemoteException()).when(mService).getHotspotNetworkConnectionStatus(); - assertThat(manager.getTetherNetworkConnectionStatus()).isNull(); + assertThat(manager.getHotspotNetworkConnectionStatus()).isNull(); } @Test - public void getTetherNetworkConnectionStatus_serviceConnected_shouldReturnStatus() + public void getHotspotNetworkConnectionStatus_serviceConnected_shouldReturnStatus() throws RemoteException { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); - TetherNetworkConnectionStatus status = new TetherNetworkConnectionStatus.Builder() - .setStatus(TetherNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT) + HotspotNetworkConnectionStatus status = new HotspotNetworkConnectionStatus.Builder() + .setStatus(HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT) .setExtras(new Bundle()).build(); manager.setService(mService); - when(mService.getTetherNetworkConnectionStatus()).thenReturn(status); + when(mService.getHotspotNetworkConnectionStatus()).thenReturn(status); - assertThat(manager.getTetherNetworkConnectionStatus()).isEqualTo(status); + assertThat(manager.getHotspotNetworkConnectionStatus()).isEqualTo(status); } @Test @@ -571,11 +575,11 @@ public class SharedConnectivityManagerTest { .thenReturn(SERVICE_PACKAGE_NAME, SERVICE_INTENT_ACTION); } - private TetherNetwork buildTetherNetwork() { - TetherNetwork.Builder builder = new TetherNetwork.Builder() + private HotspotNetwork buildHotspotNetwork() { + HotspotNetwork.Builder builder = new HotspotNetwork.Builder() .setDeviceId(DEVICE_ID) - .setDeviceInfo(DEVICE_INFO) - .setNetworkType(NETWORK_TYPE) + .setNetworkProviderInfo(NETWORK_PROVIDER_INFO) + .setHostNetworkType(NETWORK_TYPE) .setNetworkName(NETWORK_NAME) .setHotspotSsid(HOTSPOT_SSID); Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(builder::addHotspotSecurityType); @@ -583,8 +587,8 @@ public class SharedConnectivityManagerTest { } private KnownNetwork buildKnownNetwork() { - KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE) - .setSsid(SSID).setDeviceInfo(DEVICE_INFO); + KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE) + .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO); Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType); return builder.build(); } diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java index 81efa79f6df8..19effe5d6f14 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java @@ -18,11 +18,11 @@ package android.net.wifi.sharedconnectivity.service; import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP; import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP; -import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET; +import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR; +import static android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN; import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF; import static android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.CONNECTION_STATUS_SAVED; -import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR; -import static android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN; +import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET; import static com.google.common.truth.Truth.assertThat; @@ -30,12 +30,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; -import android.net.wifi.sharedconnectivity.app.DeviceInfo; +import android.net.wifi.sharedconnectivity.app.HotspotNetwork; +import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus; import android.net.wifi.sharedconnectivity.app.KnownNetwork; import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus; +import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo; import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState; -import android.net.wifi.sharedconnectivity.app.TetherNetwork; -import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus; import android.os.Bundle; import android.os.Looper; import android.os.RemoteException; @@ -55,27 +55,30 @@ import java.util.List; */ @SmallTest public class SharedConnectivityServiceTest { - private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder() - .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL") - .setConnectionStrength(2).setBatteryPercentage(50).build(); - private static final TetherNetwork TETHER_NETWORK = - new TetherNetwork.Builder().setDeviceId(1).setDeviceInfo(DEVICE_INFO) - .setNetworkType(NETWORK_TYPE_CELLULAR).setNetworkName("TEST_NETWORK") + private static final NetworkProviderInfo NETWORK_PROVIDER_INFO = + new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL") + .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2) + .setBatteryPercentage(50).build(); + private static final HotspotNetwork HOTSPOT_NETWORK = + new HotspotNetwork.Builder().setDeviceId(1).setNetworkProviderInfo( + NETWORK_PROVIDER_INFO) + .setHostNetworkType(NETWORK_TYPE_CELLULAR).setNetworkName("TEST_NETWORK") .setHotspotSsid("TEST_SSID").setHotspotBssid("TEST_BSSID") .addHotspotSecurityType(SECURITY_TYPE_WEP) .addHotspotSecurityType(SECURITY_TYPE_EAP).build(); - private static final List<TetherNetwork> TETHER_NETWORKS = List.of(TETHER_NETWORK); + private static final List<HotspotNetwork> HOTSPOT_NETWORKS = List.of(HOTSPOT_NETWORK); private static final KnownNetwork KNOWN_NETWORK = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE_NEARBY_SELF) .setSsid("TEST_SSID").addSecurityType(SECURITY_TYPE_WEP) - .addSecurityType(SECURITY_TYPE_EAP).setDeviceInfo(DEVICE_INFO).build(); + .addSecurityType(SECURITY_TYPE_EAP).setNetworkProviderInfo( + NETWORK_PROVIDER_INFO).build(); private static final List<KnownNetwork> KNOWN_NETWORKS = List.of(KNOWN_NETWORK); private static final SharedConnectivitySettingsState SETTINGS_STATE = new SharedConnectivitySettingsState.Builder().setInstantTetherEnabled(true) .setExtras(Bundle.EMPTY).build(); - private static final TetherNetworkConnectionStatus TETHER_NETWORK_CONNECTION_STATUS = - new TetherNetworkConnectionStatus.Builder().setStatus(CONNECTION_STATUS_UNKNOWN) - .setTetherNetwork(TETHER_NETWORK).setExtras(Bundle.EMPTY).build(); + private static final HotspotNetworkConnectionStatus TETHER_NETWORK_CONNECTION_STATUS = + new HotspotNetworkConnectionStatus.Builder().setStatus(CONNECTION_STATUS_UNKNOWN) + .setHotspotNetwork(HOTSPOT_NETWORK).setExtras(Bundle.EMPTY).build(); private static final KnownNetworkConnectionStatus KNOWN_NETWORK_CONNECTION_STATUS = new KnownNetworkConnectionStatus.Builder().setStatus(CONNECTION_STATUS_SAVED) .setKnownNetwork(KNOWN_NETWORK).setExtras(Bundle.EMPTY).build(); @@ -89,16 +92,20 @@ public class SharedConnectivityServiceTest { } @Override - public void onConnectTetherNetwork(@NonNull TetherNetwork network) {} + public void onConnectHotspotNetwork(@NonNull HotspotNetwork network) { + } @Override - public void onDisconnectTetherNetwork(@NonNull TetherNetwork network) {} + public void onDisconnectHotspotNetwork(@NonNull HotspotNetwork network) { + } @Override - public void onConnectKnownNetwork(@NonNull KnownNetwork network) {} + public void onConnectKnownNetwork(@NonNull KnownNetwork network) { + } @Override - public void onForgetKnownNetwork(@NonNull KnownNetwork network) {} + public void onForgetKnownNetwork(@NonNull KnownNetwork network) { + } } @Before @@ -115,15 +122,15 @@ public class SharedConnectivityServiceTest { } @Test - public void getTetherNetworks() throws RemoteException { + public void getHotspotNetworks() throws RemoteException { SharedConnectivityService service = createService(); ISharedConnectivityService.Stub binder = (ISharedConnectivityService.Stub) service.onBind(new Intent()); - service.setTetherNetworks(TETHER_NETWORKS); + service.setHotspotNetworks(HOTSPOT_NETWORKS); - assertThat(binder.getTetherNetworks()) - .containsExactlyElementsIn(List.copyOf(TETHER_NETWORKS)); + assertThat(binder.getHotspotNetworks()) + .containsExactlyElementsIn(List.copyOf(HOTSPOT_NETWORKS)); } @Test @@ -150,14 +157,14 @@ public class SharedConnectivityServiceTest { } @Test - public void updateTetherNetworkConnectionStatus() throws RemoteException { + public void updateHotspotNetworkConnectionStatus() throws RemoteException { SharedConnectivityService service = createService(); ISharedConnectivityService.Stub binder = (ISharedConnectivityService.Stub) service.onBind(new Intent()); - service.updateTetherNetworkConnectionStatus(TETHER_NETWORK_CONNECTION_STATUS); + service.updateHotspotNetworkConnectionStatus(TETHER_NETWORK_CONNECTION_STATUS); - assertThat(binder.getTetherNetworkConnectionStatus()) + assertThat(binder.getHotspotNetworkConnectionStatus()) .isEqualTo(TETHER_NETWORK_CONNECTION_STATUS); } |