Merge "Camera: Add request settings Override API"
diff --git a/Android.bp b/Android.bp
index ed7a4813..0315c12 100644
--- a/Android.bp
+++ b/Android.bp
@@ -387,6 +387,7 @@
"av-types-aidl-java",
"tv_tuner_resource_manager_aidl_interface-java",
"soundtrigger_middleware-aidl-java",
+ "modules-utils-binary-xml",
"modules-utils-build",
"modules-utils-preconditions",
"modules-utils-statemachine",
diff --git a/apct-tests/perftests/core/src/android/util/XmlPerfTest.java b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
index e05bd2a..b83657b 100644
--- a/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
+++ b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
@@ -28,6 +28,8 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.HexDump;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.Rule;
import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
index 76656bd..a31184c 100644
--- a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
+++ b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
@@ -22,6 +22,9 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.FastDataInput;
+import com.android.modules.utils.FastDataOutput;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -68,7 +71,7 @@
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
os.reset();
- final FastDataOutput out = FastDataOutput.obtainUsing4ByteSequences(os);
+ final FastDataOutput out = ArtFastDataOutput.obtain(os);
try {
doWrite(out);
out.flush();
@@ -84,7 +87,7 @@
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
os.reset();
- final FastDataOutput out = FastDataOutput.obtainUsing3ByteSequences(os);
+ final FastDataOutput out = FastDataOutput.obtain(os);
try {
doWrite(out);
out.flush();
@@ -116,7 +119,7 @@
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
is.reset();
- final FastDataInput in = FastDataInput.obtainUsing4ByteSequences(is);
+ final FastDataInput in = ArtFastDataInput.obtain(is);
try {
doRead(in);
} finally {
@@ -131,7 +134,7 @@
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
is.reset();
- final FastDataInput in = FastDataInput.obtainUsing3ByteSequences(is);
+ final FastDataInput in = FastDataInput.obtain(is);
try {
doRead(in);
} finally {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index ff9ff34..22b0968 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -41,13 +41,13 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SystemConfigFileCommitEventLogger;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.IoThread;
import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
import com.android.server.job.controllers.JobStatus;
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 27d00b7..ee448b5 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -33,12 +33,12 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArrayMap;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/api/current.txt b/core/api/current.txt
index 102deb6..997a3c1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -49944,10 +49944,13 @@
method public void clear();
method public void computeCurrentVelocity(int);
method public void computeCurrentVelocity(int, float);
+ method public float getAxisVelocity(int, int);
+ method public float getAxisVelocity(int);
method public float getXVelocity();
method public float getXVelocity(int);
method public float getYVelocity();
method public float getYVelocity(int);
+ method public boolean isAxisSupported(int);
method public static android.view.VelocityTracker obtain();
method public void recycle();
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 74329a3..d6c10ae 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -81,8 +81,6 @@
import android.util.DisplayMetrics;
import android.util.Singleton;
import android.util.Size;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.window.TaskSnapshot;
import com.android.internal.app.LocalePicker;
@@ -92,6 +90,8 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import java.io.FileDescriptor;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index b803070..4b1b0a2 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -221,6 +221,12 @@
public abstract boolean isSystemReady();
/**
+ * @return {@code true} if system is using the "modern" broadcast queue,
+ * {@code false} otherwise.
+ */
+ public abstract boolean isModernQueueEnabled();
+
+ /**
* Returns package name given pid.
*
* @param pid The pid we are searching package name for.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3f39026..d1275f6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -867,7 +867,7 @@
// when adding one of these:
// - increment _NUM_OP
- // - define an OPSTR_* constant (marked as @SystemApi)
+ // - define an OPSTR_* constant (and mark as @SystemApi if needed)
// - add row to sAppOpInfos
// - add descriptive strings to Settings/res/values/arrays.xml
// - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index be53a62..0e2b098 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -174,7 +174,7 @@
@TestApi
public void setSystemLocales(@NonNull LocaleList locales) {
try {
- Configuration conf = ActivityManager.getService().getConfiguration();
+ Configuration conf = new Configuration();
conf.setLocales(locales);
ActivityManager.getService().updatePersistentConfiguration(conf);
} catch (RemoteException e) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 7215987..9615b68 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -33,12 +33,12 @@
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.json.JSONException;
import org.json.JSONObject;
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 5c29eb3..3bd86c1 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -23,10 +23,11 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.json.JSONException;
import org.json.JSONObject;
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 5b0bd96..0f26818 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -175,6 +175,23 @@
"file_patterns": [
"(/|^)KeyguardManager.java"
]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.app.PropertyInvalidatedCacheTests"
+ }
+ ],
+ "file_patterns": [
+ "(/|^)PropertyInvalidatedCache.java"
+ ]
}
],
"presubmit-large": [
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 41256d0..67408a4 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -37,10 +37,11 @@
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 7e95177..efa23dd 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -27,8 +27,9 @@
import android.os.Parcelable;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/app/admin/ParcelableResource.java b/core/java/android/app/admin/ParcelableResource.java
index a297665..5b438f8 100644
--- a/core/java/android/app/admin/ParcelableResource.java
+++ b/core/java/android/app/admin/ParcelableResource.java
@@ -30,8 +30,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
index 63c9839..b0ea499 100644
--- a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
@@ -27,8 +27,9 @@
import android.os.Parcelable;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index b88bf76..9e6c91f 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -22,8 +22,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 68ac4cc..b100eb2 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -26,8 +26,9 @@
import android.os.Parcelable;
import android.util.Log;
import android.util.Pair;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 495f94f..bf9dc8e 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -25,10 +25,10 @@
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 56b8bd8..2b40fdf 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -28,10 +28,10 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 823c142..aa86af9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2205,6 +2205,13 @@
*/
public static final int INSTALL_ACTIVATION_FAILED = -128;
+ /**
+ * Installation failed return code: requesting user pre-approval is currently unavailable.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE = -129;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -9643,6 +9650,7 @@
case INSTALL_FAILED_NO_MATCHING_ABIS: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;
case INSTALL_FAILED_MISSING_SPLIT: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE: return PackageInstaller.STATUS_FAILURE_BLOCKED;
default: return PackageInstaller.STATUS_FAILURE;
}
}
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 78984bd..104527e 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -36,14 +36,14 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index d94b0d8..b049880 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -21,9 +21,9 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.ArrayUtils;
+import com.android.modules.utils.TypedXmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.IOException;
diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java
index 23945ee..8786f7c 100644
--- a/core/java/android/content/pm/SuspendDialogInfo.java
+++ b/core/java/android/content/pm/SuspendDialogInfo.java
@@ -29,11 +29,11 @@
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import java.io.IOException;
import java.lang.annotation.Retention;
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index b345d50..645a1ac 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -22,10 +22,10 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/pm/XmlSerializerAndParser.java b/core/java/android/content/pm/XmlSerializerAndParser.java
index 51cd6ca..d748aa1 100644
--- a/core/java/android/content/pm/XmlSerializerAndParser.java
+++ b/core/java/android/content/pm/XmlSerializerAndParser.java
@@ -17,10 +17,10 @@
package android.content.pm;
import android.compat.annotation.UnsupportedAppUsage;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/credentials/Credential.java b/core/java/android/credentials/Credential.java
index a247d16..fed2592 100644
--- a/core/java/android/credentials/Credential.java
+++ b/core/java/android/credentials/Credential.java
@@ -32,6 +32,13 @@
public final class Credential implements Parcelable {
/**
+ * The type value for password credential related operations.
+ *
+ * @hide
+ */
+ @NonNull public static final String TYPE_PASSWORD = "android.credentials.TYPE_PASSWORD";
+
+ /**
* The credential type.
*/
@NonNull
diff --git a/core/java/android/credentials/ui/Entry.java b/core/java/android/credentials/ui/Entry.java
index b9ee72d..33427d3 100644
--- a/core/java/android/credentials/ui/Entry.java
+++ b/core/java/android/credentials/ui/Entry.java
@@ -82,32 +82,46 @@
public static final String EXTRA_ENTRY_AUTHENTICATION_ACTION =
"android.credentials.ui.extra.ENTRY_AUTHENTICATION_ACTION";
- // TODO: change to string key + string subkey.
- private final int mId;
+ @NonNull private final String mKey;
+ @NonNull private final String mSubkey;
@NonNull
private final Slice mSlice;
protected Entry(@NonNull Parcel in) {
- int entryId = in.readInt();
+ String key = in.readString8();
+ String subkey = in.readString8();
Slice slice = Slice.CREATOR.createFromParcel(in);
- mId = entryId;
+ mKey = key;
+ AnnotationValidations.validate(NonNull.class, null, mKey);
+ mSubkey = subkey;
+ AnnotationValidations.validate(NonNull.class, null, mSubkey);
mSlice = slice;
AnnotationValidations.validate(NonNull.class, null, mSlice);
}
- public Entry(int id, @NonNull Slice slice) {
- mId = id;
+ public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice) {
+ mKey = key;
+ mSubkey = subkey;
mSlice = slice;
}
/**
- * Returns the id of this entry that's unique within the context of the CredentialManager
+ * Returns the identifier of this entry that's unique within the context of the CredentialManager
* request.
*/
- public int getEntryId() {
- return mId;
+ @NonNull
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * Returns the sub-identifier of this entry that's unique within the context of the {@code key}.
+ */
+ @NonNull
+ public String getSubkey() {
+ return mSubkey;
}
/**
@@ -120,7 +134,8 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mId);
+ dest.writeString8(mKey);
+ dest.writeString8(mSubkey);
mSlice.writeToParcel(dest, flags);
}
diff --git a/core/java/android/credentials/ui/UserSelectionDialogResult.java b/core/java/android/credentials/ui/UserSelectionDialogResult.java
index eb3a4a8..6025d78 100644
--- a/core/java/android/credentials/ui/UserSelectionDialogResult.java
+++ b/core/java/android/credentials/ui/UserSelectionDialogResult.java
@@ -54,18 +54,17 @@
private static final String EXTRA_USER_SELECTION_RESULT =
"android.credentials.ui.extra.USER_SELECTION_RESULT";
- @NonNull
- private final String mProviderId;
-
- // TODO: consider switching to string or other types, depending on the service implementation.
- private final int mEntryId;
+ @NonNull private final String mProviderId;
+ @NonNull private final String mEntryKey;
+ @NonNull private final String mEntrySubkey;
public UserSelectionDialogResult(
@NonNull IBinder requestToken, @NonNull String providerId,
- int entryId) {
+ @NonNull String entryKey, @NonNull String entrySubkey) {
super(requestToken);
mProviderId = providerId;
- mEntryId = entryId;
+ mEntryKey = entryKey;
+ mEntrySubkey = entrySubkey;
}
/** Returns provider package name whose entry was selected by the user. */
@@ -74,26 +73,38 @@
return mProviderId;
}
- /** Returns the id of the visual entry that the user selected. */
- public int getEntryId() {
- return mEntryId;
+ /** Returns the key of the visual entry that the user selected. */
+ @NonNull
+ public String getEntryKey() {
+ return mEntryKey;
+ }
+
+ /** Returns the subkey of the visual entry that the user selected. */
+ @NonNull
+ public String getEntrySubkey() {
+ return mEntrySubkey;
}
protected UserSelectionDialogResult(@NonNull Parcel in) {
super(in);
String providerId = in.readString8();
- int entryId = in.readInt();
+ String entryKey = in.readString8();
+ String entrySubkey = in.readString8();
mProviderId = providerId;
AnnotationValidations.validate(NonNull.class, null, mProviderId);
- mEntryId = entryId;
+ mEntryKey = entryKey;
+ AnnotationValidations.validate(NonNull.class, null, mEntryKey);
+ mEntrySubkey = entrySubkey;
+ AnnotationValidations.validate(NonNull.class, null, mEntrySubkey);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString8(mProviderId);
- dest.writeInt(mEntryId);
+ dest.writeString8(mEntryKey);
+ dest.writeString8(mEntrySubkey);
}
@Override
diff --git a/core/java/android/graphics/fonts/FontUpdateRequest.java b/core/java/android/graphics/fonts/FontUpdateRequest.java
index dae09f0..510985c 100644
--- a/core/java/android/graphics/fonts/FontUpdateRequest.java
+++ b/core/java/android/graphics/fonts/FontUpdateRequest.java
@@ -24,7 +24,8 @@
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.text.FontConfig;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 366734e..007b37f 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -24,11 +24,11 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index 2919ec3..5ff08ba 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -23,10 +23,10 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.MathUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
index 76ee097..f8e2558 100644
--- a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
+++ b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
@@ -37,7 +37,7 @@
import android.util.AtomicFile;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastDataInput;
+import com.android.internal.util.ArtFastDataInput;
import libcore.io.IoUtils;
@@ -254,7 +254,7 @@
private static void readPlatformCollection(@NonNull NetworkStatsCollection.Builder builder,
@NonNull File file) throws IOException {
final FileInputStream is = new FileInputStream(file);
- final FastDataInput dataIn = new FastDataInput(is, BUFFER_SIZE);
+ final ArtFastDataInput dataIn = new ArtFastDataInput(is, BUFFER_SIZE);
try {
readPlatformCollection(builder, dataIn);
} finally {
diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java
index 068df22..7a153ef 100644
--- a/core/java/android/os/AggregateBatteryConsumer.java
+++ b/core/java/android/os/AggregateBatteryConsumer.java
@@ -17,10 +17,11 @@
package android.os;
import android.annotation.NonNull;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 0c5f778..e2c52ce 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -22,12 +22,12 @@
import android.database.CursorWindow;
import android.util.Range;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index acfd15c..02704f5 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -22,12 +22,12 @@
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 522807b..5dffa0a 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -22,10 +22,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index d2d6bec..4a6772d 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -20,8 +20,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.TextUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index e1ec5cd..6b4a5cf 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -17,8 +17,9 @@
package android.os;
import android.annotation.NonNull;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index e285b1c..eb9901a 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -48,12 +48,12 @@
import android.util.ArraySet;
import android.util.PluralsMessageFormatter;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java
index 3b08c3b..7c83087 100644
--- a/core/java/android/util/CharsetUtils.java
+++ b/core/java/android/util/CharsetUtils.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
+import com.android.modules.utils.ModifiedUtf8;
+
import dalvik.annotation.optimization.FastNative;
/**
@@ -30,8 +32,7 @@
* Callers are cautioned that there is a long-standing ART bug that emits
* non-standard 4-byte sequences, as described by {@code kUtfUse4ByteSequence}
* in {@code art/runtime/jni/jni_internal.cc}. If precise modified UTF-8
- * encoding is required, use {@link com.android.internal.util.ModifiedUtf8}
- * instead.
+ * encoding is required, use {@link ModifiedUtf8} instead.
*
* @hide
*/
@@ -43,8 +44,8 @@
* Callers are cautioned that there is a long-standing ART bug that emits
* non-standard 4-byte sequences, as described by
* {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}.
- * If precise modified UTF-8 encoding is required, use
- * {@link com.android.internal.util.ModifiedUtf8} instead.
+ * If precise modified UTF-8 encoding is required, use {@link ModifiedUtf8}
+ * instead.
*
* @param src string value to be encoded
* @param dest destination byte array to encode into
@@ -66,8 +67,8 @@
* Callers are cautioned that there is a long-standing ART bug that emits
* non-standard 4-byte sequences, as described by
* {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}.
- * If precise modified UTF-8 encoding is required, use
- * {@link com.android.internal.util.ModifiedUtf8} instead.
+ * If precise modified UTF-8 encoding is required, use {@link ModifiedUtf8}
+ * instead.
*
* @param src string value to be encoded
* @param srcLen exact length of string to be encoded
@@ -88,8 +89,8 @@
* Callers are cautioned that there is a long-standing ART bug that emits
* non-standard 4-byte sequences, as described by
* {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}.
- * If precise modified UTF-8 encoding is required, use
- * {@link com.android.internal.util.ModifiedUtf8} instead.
+ * If precise modified UTF-8 encoding is required, use {@link ModifiedUtf8}
+ * instead.
*
* @param src source byte array to decode from
* @param srcOff offset into source where decoding should begin
diff --git a/core/java/android/util/TypedXmlPullParser.java b/core/java/android/util/TypedXmlPullParser.java
deleted file mode 100644
index aa68bf4..0000000
--- a/core/java/android/util/TypedXmlPullParser.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- * Specialization of {@link XmlPullParser} which adds explicit methods to
- * support consistent and efficient conversion of primitive data types.
- *
- * @hide
- */
-public interface TypedXmlPullParser extends XmlPullParser {
- /**
- * @return index of requested attribute, otherwise {@code -1} if undefined
- */
- default int getAttributeIndex(@Nullable String namespace, @NonNull String name) {
- final boolean namespaceNull = (namespace == null);
- final int count = getAttributeCount();
- for (int i = 0; i < count; i++) {
- if ((namespaceNull || namespace.equals(getAttributeNamespace(i)))
- && name.equals(getAttributeName(i))) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * @return index of requested attribute
- * @throws XmlPullParserException if the value is undefined
- */
- default int getAttributeIndexOrThrow(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) {
- throw new XmlPullParserException("Missing attribute " + name);
- } else {
- return index;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- @NonNull byte[] getAttributeBytesHex(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- @NonNull byte[] getAttributeBytesBase64(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- int getAttributeInt(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- int getAttributeIntHex(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- long getAttributeLong(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- long getAttributeLongHex(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- float getAttributeFloat(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- double getAttributeDouble(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed
- */
- boolean getAttributeBoolean(int index) throws XmlPullParserException;
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default @NonNull byte[] getAttributeBytesHex(@Nullable String namespace,
- @NonNull String name) throws XmlPullParserException {
- return getAttributeBytesHex(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default @NonNull byte[] getAttributeBytesBase64(@Nullable String namespace,
- @NonNull String name) throws XmlPullParserException {
- return getAttributeBytesBase64(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default int getAttributeInt(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeInt(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default int getAttributeIntHex(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeIntHex(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default long getAttributeLong(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeLong(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default long getAttributeLongHex(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeLongHex(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default float getAttributeFloat(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeFloat(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default double getAttributeDouble(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeDouble(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}
- * @throws XmlPullParserException if the value is malformed or undefined
- */
- default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name)
- throws XmlPullParserException {
- return getAttributeBoolean(getAttributeIndexOrThrow(namespace, name));
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default @Nullable byte[] getAttributeBytesHex(@Nullable String namespace,
- @NonNull String name, @Nullable byte[] defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeBytesHex(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default @Nullable byte[] getAttributeBytesBase64(@Nullable String namespace,
- @NonNull String name, @Nullable byte[] defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeBytesBase64(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default int getAttributeInt(@Nullable String namespace, @NonNull String name,
- int defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeInt(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default int getAttributeIntHex(@Nullable String namespace, @NonNull String name,
- int defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeIntHex(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default long getAttributeLong(@Nullable String namespace, @NonNull String name,
- long defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeLong(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default long getAttributeLongHex(@Nullable String namespace, @NonNull String name,
- long defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeLongHex(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default float getAttributeFloat(@Nullable String namespace, @NonNull String name,
- float defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeFloat(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default double getAttributeDouble(@Nullable String namespace, @NonNull String name,
- double defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeDouble(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-
- /**
- * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
- * default value if the value is malformed or undefined
- */
- default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name,
- boolean defaultValue) {
- final int index = getAttributeIndex(namespace, name);
- if (index == -1) return defaultValue;
- try {
- return getAttributeBoolean(index);
- } catch (Exception ignored) {
- return defaultValue;
- }
- }
-}
diff --git a/core/java/android/util/TypedXmlSerializer.java b/core/java/android/util/TypedXmlSerializer.java
deleted file mode 100644
index 3f9eaa8..0000000
--- a/core/java/android/util/TypedXmlSerializer.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-
-/**
- * Specialization of {@link XmlSerializer} which adds explicit methods to
- * support consistent and efficient conversion of primitive data types.
- *
- * @hide
- */
-public interface TypedXmlSerializer extends XmlSerializer {
- /**
- * Functionally equivalent to {@link #attribute(String, String, String)} but
- * with the additional signal that the given value is a candidate for being
- * canonicalized, similar to {@link String#intern()}.
- */
- @NonNull XmlSerializer attributeInterned(@Nullable String namespace, @NonNull String name,
- @NonNull String value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeBytesHex(@Nullable String namespace, @NonNull String name,
- @NonNull byte[] value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeBytesBase64(@Nullable String namespace, @NonNull String name,
- @NonNull byte[] value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeInt(@Nullable String namespace, @NonNull String name,
- int value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeIntHex(@Nullable String namespace, @NonNull String name,
- int value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeLong(@Nullable String namespace, @NonNull String name,
- long value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeLongHex(@Nullable String namespace, @NonNull String name,
- long value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeFloat(@Nullable String namespace, @NonNull String name,
- float value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeDouble(@Nullable String namespace, @NonNull String name,
- double value) throws IOException;
-
- /**
- * Encode the given strongly-typed value and serialize using
- * {@link #attribute(String, String, String)}.
- */
- @NonNull XmlSerializer attributeBoolean(@Nullable String namespace, @NonNull String name,
- boolean value) throws IOException;
-}
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index 38decf9..33058d8 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -22,10 +22,13 @@
import android.system.ErrnoException;
import android.system.Os;
-import com.android.internal.util.BinaryXmlPullParser;
-import com.android.internal.util.BinaryXmlSerializer;
+import com.android.internal.util.ArtBinaryXmlPullParser;
+import com.android.internal.util.ArtBinaryXmlSerializer;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.BinaryXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.util.XmlObjectFactory;
@@ -146,7 +149,7 @@
* @hide
*/
public static @NonNull TypedXmlPullParser newBinaryPullParser() {
- return new BinaryXmlPullParser();
+ return new ArtBinaryXmlPullParser();
}
/**
@@ -225,7 +228,7 @@
* @hide
*/
public static @NonNull TypedXmlSerializer newBinarySerializer() {
- return new BinaryXmlSerializer();
+ return new ArtBinaryXmlSerializer();
}
/**
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index a52fc75..6d25523 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -183,6 +183,7 @@
private static native float nativeGetVelocity(long ptr, int axis, int id);
private static native boolean nativeGetEstimator(
long ptr, int axis, int id, Estimator outEstimator);
+ private static native boolean nativeIsAxisSupported(int axis);
static {
// Strategy string and IDs mapping lookup.
@@ -305,6 +306,22 @@
}
/**
+ * Checks whether a given motion axis is supported for velocity tracking.
+ *
+ * <p>The axis values that would make sense to use for this method are the ones defined in the
+ * {@link MotionEvent} class.
+ *
+ * @param axis The axis to check for velocity support.
+ * @return {@code true} if {@code axis} is supported for velocity tracking, or {@code false}
+ * otherwise.
+ * @see #getAxisVelocity(int, int)
+ * @see #getAxisVelocity(int)
+ */
+ public boolean isAxisSupported(int axis) {
+ return nativeIsAxisSupported(axis);
+ }
+
+ /**
* Reset the velocity tracker back to its initial state.
*/
public void clear() {
@@ -345,7 +362,9 @@
* {@link #getYVelocity()}.
*
* @param units The units you would like the velocity in. A value of 1
- * provides pixels per millisecond, 1000 provides pixels per second, etc.
+ * provides units per millisecond, 1000 provides units per second, etc.
+ * Note that the units referred to here are the same units with which motion is reported. For
+ * axes X and Y, the units are pixels.
* @param maxVelocity The maximum velocity that can be computed by this method.
* This value must be declared in the same unit as the units parameter. This value
* must be positive.
@@ -397,6 +416,45 @@
}
/**
+ * Retrieve the last computed velocity for a given motion axis. You must first call
+ * {@link #computeCurrentVelocity(int)} or {@link #computeCurrentVelocity(int, float)} before
+ * calling this function.
+ *
+ * <p>In addition to {@link MotionEvent#AXIS_X} and {@link MotionEvent#AXIS_Y} which have been
+ * supported since the introduction of this class, the following axes are supported for this
+ * method:
+ * <ul>
+ * <li> {@link MotionEvent#AXIS_SCROLL}: supported starting
+ * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}
+ * </ul>
+ *
+ * @param axis Which axis' velocity to return.
+ * @param id Which pointer's velocity to return.
+ * @return The previously computed velocity for {@code axis} for pointer ID of {@code id} if
+ * {@code axis} is supported for velocity tracking, or 0 if velocity tracking is not supported
+ * for the axis.
+ * @see #isAxisSupported(int)
+ */
+ public float getAxisVelocity(int axis, int id) {
+ return nativeGetVelocity(mPtr, axis, id);
+ }
+
+ /**
+ * Equivalent to calling {@link #getAxisVelocity(int, int)} for {@code axis} and the active
+ * pointer.
+ *
+ * @param axis Which axis' velocity to return.
+ * @return The previously computed velocity for {@code axis} for the active pointer if
+ * {@code axis} is supported for velocity tracking, or 0 if velocity tracking is not supported
+ * for the axis.
+ * @see #isAxisSupported(int)
+ * @see #getAxisVelocity(int, int)
+ */
+ public float getAxisVelocity(int axis) {
+ return nativeGetVelocity(mPtr, axis, ACTIVE_POINTER_ID);
+ }
+
+ /**
* Get an estimator for the movements of a pointer using past movements of the
* pointer to predict future movements.
*
@@ -426,8 +484,8 @@
* Past estimated positions are at negative times and future estimated positions
* are at positive times.
*
- * First coefficient is position (in pixels), second is velocity (in pixels per second),
- * third is acceleration (in pixels per second squared).
+ * First coefficient is position (in units), second is velocity (in units per second),
+ * third is acceleration (in units per second squared).
*
* @hide For internal use only. Not a final API.
*/
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 121839b..bdfcb03 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -23,6 +24,7 @@
import android.content.res.Configuration;
import android.icu.text.DisplayContext;
import android.icu.text.LocaleDisplayNames;
+import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -74,6 +76,10 @@
/** {@hide} */
public static final int SUBTYPE_ID_NONE = 0;
+ private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
+
+ private static final String UNDEFINED_LANGUAGE_TAG = "und";
+
private final boolean mIsAuxiliary;
private final boolean mOverridesImplicitlyEnabledSubtype;
private final boolean mIsAsciiCapable;
@@ -90,6 +96,14 @@
private volatile HashMap<String, String> mExtraValueHashMapCache;
/**
+ * A volatile cache to optimize {@link #getCanonicalizedLanguageTag()}.
+ *
+ * <p>{@code null} means that the initial evaluation is not yet done.</p>
+ */
+ @Nullable
+ private volatile String mCachedCanonicalizedLanguageTag;
+
+ /**
* InputMethodSubtypeBuilder is a builder class of InputMethodSubtype.
* This class is designed to be used with
* {@link android.view.inputmethod.InputMethodManager#setAdditionalInputMethodSubtypes}.
@@ -392,6 +406,65 @@
}
/**
+ * Returns a canonicalized BCP 47 Language Tag initialized with {@link #getLocaleObject()}.
+ *
+ * <p>This has an internal cache mechanism. Subsequent calls are in general cheap and fast.</p>
+ *
+ * @return a canonicalized BCP 47 Language Tag initialized with {@link #getLocaleObject()}. An
+ * empty string if {@link #getLocaleObject()} returns {@code null} or an empty
+ * {@link Locale} object.
+ * @hide
+ */
+ @AnyThread
+ @NonNull
+ public String getCanonicalizedLanguageTag() {
+ final String cachedValue = mCachedCanonicalizedLanguageTag;
+ if (cachedValue != null) {
+ return cachedValue;
+ }
+
+ String result = null;
+ final Locale locale = getLocaleObject();
+ if (locale != null) {
+ final String langTag = locale.toLanguageTag();
+ if (!TextUtils.isEmpty(langTag)) {
+ result = ULocale.createCanonical(ULocale.forLanguageTag(langTag)).toLanguageTag();
+ }
+ }
+ result = TextUtils.emptyIfNull(result);
+ mCachedCanonicalizedLanguageTag = result;
+ return result;
+ }
+
+ /**
+ * Determines whether this {@link InputMethodSubtype} can be used as the key of mapping rules
+ * between {@link InputMethodSubtype} and hardware keyboard layout.
+ *
+ * <p>Note that in a future build may require different rules. Design the system so that the
+ * system can automatically take care of any rule changes upon OTAs.</p>
+ *
+ * @return {@code true} if this {@link InputMethodSubtype} can be used as the key of mapping
+ * rules between {@link InputMethodSubtype} and hardware keyboard layout.
+ * @hide
+ */
+ public boolean isSuitableForPhysicalKeyboardLayoutMapping() {
+ if (hashCode() == SUBTYPE_ID_NONE) {
+ return false;
+ }
+ if (!TextUtils.equals(getMode(), SUBTYPE_MODE_KEYBOARD)) {
+ return false;
+ }
+ if (isAuxiliary()) {
+ return false;
+ }
+ final String langTag = getCanonicalizedLanguageTag();
+ if (langTag.isEmpty() || TextUtils.equals(langTag, UNDEFINED_LANGUAGE_TAG)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* @return The mode of the subtype.
*/
public String getMode() {
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 999be08..65372be 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -314,8 +314,7 @@
try {
final IActivityManager am = ActivityManager.getService();
- final Configuration config = am.getConfiguration();
-
+ final Configuration config = new Configuration();
config.setLocales(locales);
config.userSetLocale = true;
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java b/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java
index f0fe573..5392bdc 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java
+++ b/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java
@@ -155,4 +155,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Invokes {@link IInputMethodManager#removeImeSurface()}
+ */
+ @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
+ @AnyThread
+ public static void removeImeSurface(@Nullable Consumer<RemoteException> exceptionHandler) {
+ final IInputMethodManager service = getService();
+ if (service == null) {
+ return;
+ }
+ try {
+ service.removeImeSurface();
+ } catch (RemoteException e) {
+ handleRemoteExceptionOrRethrow(e, exceptionHandler);
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java b/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java
new file mode 100644
index 0000000..c56bc49
--- /dev/null
+++ b/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java
@@ -0,0 +1,39 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+
+import com.android.modules.utils.BinaryXmlPullParser;
+import com.android.modules.utils.FastDataInput;
+
+import java.io.DataInput;
+import java.io.InputStream;
+
+/**
+ * {@inheritDoc}
+ * <p>
+ * This decodes large code-points using 4-byte sequences, and <em>is not</em> compatible with the
+ * {@link DataInput} API contract, which specifies that large code-points must be encoded with
+ * 3-byte sequences.
+ */
+public class ArtBinaryXmlPullParser extends BinaryXmlPullParser {
+ @NonNull
+ protected FastDataInput obtainFastDataInput(@NonNull InputStream is) {
+ return ArtFastDataInput.obtain(is);
+ }
+}
diff --git a/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java b/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java
new file mode 100644
index 0000000..98a2135
--- /dev/null
+++ b/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+
+import com.android.modules.utils.BinaryXmlSerializer;
+import com.android.modules.utils.FastDataOutput;
+
+import java.io.DataOutput;
+import java.io.OutputStream;
+
+/**
+ * {@inheritDoc}
+ * <p>
+ * This encodes large code-points using 4-byte sequences and <em>is not</em> compatible with the
+ * {@link DataOutput} API contract, which specifies that large code-points must be encoded with
+ * 3-byte sequences.
+ */
+public class ArtBinaryXmlSerializer extends BinaryXmlSerializer {
+ @NonNull
+ @Override
+ protected FastDataOutput obtainFastDataOutput(@NonNull OutputStream os) {
+ return ArtFastDataOutput.obtain(os);
+ }
+}
diff --git a/core/java/com/android/internal/util/ArtFastDataInput.java b/core/java/com/android/internal/util/ArtFastDataInput.java
new file mode 100644
index 0000000..3e8916c
--- /dev/null
+++ b/core/java/com/android/internal/util/ArtFastDataInput.java
@@ -0,0 +1,94 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+import android.util.CharsetUtils;
+
+import com.android.modules.utils.FastDataInput;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * {@inheritDoc}
+ * <p>
+ * This decodes large code-points using 4-byte sequences, and <em>is not</em> compatible with the
+ * {@link DataInput} API contract, which specifies that large code-points must be encoded with
+ * 3-byte sequences.
+ */
+public class ArtFastDataInput extends FastDataInput {
+ private static AtomicReference<ArtFastDataInput> sInCache = new AtomicReference<>();
+
+ private final long mBufferPtr;
+
+ public ArtFastDataInput(@NonNull InputStream in, int bufferSize) {
+ super(in, bufferSize);
+
+ mBufferPtr = mRuntime.addressOf(mBuffer);
+ }
+
+ /**
+ * Obtain a {@link ArtFastDataInput} configured with the given
+ * {@link InputStream} and which decodes large code-points using 4-byte
+ * sequences.
+ * <p>
+ * This <em>is not</em> compatible with the {@link DataInput} API contract,
+ * which specifies that large code-points must be encoded with 3-byte
+ * sequences.
+ */
+ public static ArtFastDataInput obtain(@NonNull InputStream in) {
+ ArtFastDataInput instance = sInCache.getAndSet(null);
+ if (instance != null) {
+ instance.setInput(in);
+ return instance;
+ }
+ return new ArtFastDataInput(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Release a {@link ArtFastDataInput} to potentially be recycled. You must not
+ * interact with the object after releasing it.
+ */
+ public void release() {
+ super.release();
+
+ if (mBufferCap == DEFAULT_BUFFER_SIZE) {
+ // Try to return to the cache.
+ sInCache.compareAndSet(null, this);
+ }
+ }
+
+ @Override
+ public String readUTF() throws IOException {
+ // Attempt to read directly from buffer space if there's enough room,
+ // otherwise fall back to chunking into place
+ final int len = readUnsignedShort();
+ if (mBufferCap > len) {
+ if (mBufferLim - mBufferPos < len) fill(len);
+ final String res = CharsetUtils.fromModifiedUtf8Bytes(mBufferPtr, mBufferPos, len);
+ mBufferPos += len;
+ return res;
+ } else {
+ final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
+ readFully(tmp, 0, len);
+ return CharsetUtils.fromModifiedUtf8Bytes(mRuntime.addressOf(tmp), 0, len);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/ArtFastDataOutput.java b/core/java/com/android/internal/util/ArtFastDataOutput.java
new file mode 100644
index 0000000..ac595b6
--- /dev/null
+++ b/core/java/com/android/internal/util/ArtFastDataOutput.java
@@ -0,0 +1,103 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+import android.util.CharsetUtils;
+
+import com.android.modules.utils.FastDataOutput;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * {@inheritDoc}
+ * <p>
+ * This encodes large code-points using 4-byte sequences and <em>is not</em> compatible with the
+ * {@link DataOutput} API contract, which specifies that large code-points must be encoded with
+ * 3-byte sequences.
+ */
+public class ArtFastDataOutput extends FastDataOutput {
+ private static AtomicReference<ArtFastDataOutput> sOutCache = new AtomicReference<>();
+
+ private final long mBufferPtr;
+
+ public ArtFastDataOutput(@NonNull OutputStream out, int bufferSize) {
+ super(out, bufferSize);
+
+ mBufferPtr = mRuntime.addressOf(mBuffer);
+ }
+
+ /**
+ * Obtain an {@link ArtFastDataOutput} configured with the given
+ * {@link OutputStream} and which encodes large code-points using 4-byte
+ * sequences.
+ * <p>
+ * This <em>is not</em> compatible with the {@link DataOutput} API contract,
+ * which specifies that large code-points must be encoded with 3-byte
+ * sequences.
+ */
+ public static ArtFastDataOutput obtain(@NonNull OutputStream out) {
+ ArtFastDataOutput instance = sOutCache.getAndSet(null);
+ if (instance != null) {
+ instance.setOutput(out);
+ return instance;
+ }
+ return new ArtFastDataOutput(out, DEFAULT_BUFFER_SIZE);
+ }
+
+ @Override
+ public void release() {
+ super.release();
+
+ if (mBufferCap == DEFAULT_BUFFER_SIZE) {
+ // Try to return to the cache.
+ sOutCache.compareAndSet(null, this);
+ }
+ }
+
+ @Override
+ public void writeUTF(String s) throws IOException {
+ // Attempt to write directly to buffer space if there's enough room,
+ // otherwise fall back to chunking into place
+ if (mBufferCap - mBufferPos < 2 + s.length()) drain();
+
+ // Magnitude of this returned value indicates the number of bytes
+ // required to encode the string; sign indicates success/failure
+ int len = CharsetUtils.toModifiedUtf8Bytes(s, mBufferPtr, mBufferPos + 2, mBufferCap);
+ if (Math.abs(len) > MAX_UNSIGNED_SHORT) {
+ throw new IOException("Modified UTF-8 length too large: " + len);
+ }
+
+ if (len >= 0) {
+ // Positive value indicates the string was encoded into the buffer
+ // successfully, so we only need to prefix with length
+ writeShort(len);
+ mBufferPos += len;
+ } else {
+ // Negative value indicates buffer was too small and we need to
+ // allocate a temporary buffer for encoding
+ len = -len;
+ final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
+ CharsetUtils.toModifiedUtf8Bytes(s, mRuntime.addressOf(tmp), 0, tmp.length);
+ writeShort(len);
+ write(tmp, 0, len);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java
deleted file mode 100644
index d3abac9..0000000
--- a/core/java/com/android/internal/util/BinaryXmlPullParser.java
+++ /dev/null
@@ -1,939 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import static com.android.internal.util.BinaryXmlSerializer.ATTRIBUTE;
-import static com.android.internal.util.BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_FALSE;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_TRUE;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_BASE64;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_HEX;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_DOUBLE;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_FLOAT;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT_HEX;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG_HEX;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_NULL;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING;
-import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING_INTERNED;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * Parser that reads XML documents using a custom binary wire protocol which
- * benchmarking has shown to be 8.5x faster than {@link Xml.newFastPullParser()}
- * for a typical {@code packages.xml}.
- * <p>
- * The high-level design of the wire protocol is to directly serialize the event
- * stream, while efficiently and compactly writing strongly-typed primitives
- * delivered through the {@link TypedXmlSerializer} interface.
- * <p>
- * Each serialized event is a single byte where the lower half is a normal
- * {@link XmlPullParser} token and the upper half is an optional data type
- * signal, such as {@link #TYPE_INT}.
- * <p>
- * This parser has some specific limitations:
- * <ul>
- * <li>Only the UTF-8 encoding is supported.
- * <li>Variable length values, such as {@code byte[]} or {@link String}, are
- * limited to 65,535 bytes in length. Note that {@link String} values are stored
- * as UTF-8 on the wire.
- * <li>Namespaces, prefixes, properties, and options are unsupported.
- * </ul>
- */
-public final class BinaryXmlPullParser implements TypedXmlPullParser {
- private FastDataInput mIn;
-
- private int mCurrentToken = START_DOCUMENT;
- private int mCurrentDepth = 0;
- private String mCurrentName;
- private String mCurrentText;
-
- /**
- * Pool of attributes parsed for the currently tag. All interactions should
- * be done via {@link #obtainAttribute()}, {@link #findAttribute(String)},
- * and {@link #resetAttributes()}.
- */
- private int mAttributeCount = 0;
- private Attribute[] mAttributes;
-
- @Override
- public void setInput(InputStream is, String encoding) throws XmlPullParserException {
- if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
- throw new UnsupportedOperationException();
- }
-
- if (mIn != null) {
- mIn.release();
- mIn = null;
- }
-
- mIn = FastDataInput.obtainUsing4ByteSequences(is);
-
- mCurrentToken = START_DOCUMENT;
- mCurrentDepth = 0;
- mCurrentName = null;
- mCurrentText = null;
-
- mAttributeCount = 0;
- mAttributes = new Attribute[8];
- for (int i = 0; i < mAttributes.length; i++) {
- mAttributes[i] = new Attribute();
- }
-
- try {
- final byte[] magic = new byte[4];
- mIn.readFully(magic);
- if (!Arrays.equals(magic, PROTOCOL_MAGIC_VERSION_0)) {
- throw new IOException("Unexpected magic " + bytesToHexString(magic));
- }
-
- // We're willing to immediately consume a START_DOCUMENT if present,
- // but we're okay if it's missing
- if (peekNextExternalToken() == START_DOCUMENT) {
- consumeToken();
- }
- } catch (IOException e) {
- throw new XmlPullParserException(e.toString());
- }
- }
-
- @Override
- public void setInput(Reader in) throws XmlPullParserException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int next() throws XmlPullParserException, IOException {
- while (true) {
- final int token = nextToken();
- switch (token) {
- case START_TAG:
- case END_TAG:
- case END_DOCUMENT:
- return token;
- case TEXT:
- consumeAdditionalText();
- // Per interface docs, empty text regions are skipped
- if (mCurrentText == null || mCurrentText.length() == 0) {
- continue;
- } else {
- return TEXT;
- }
- }
- }
- }
-
- @Override
- public int nextToken() throws XmlPullParserException, IOException {
- if (mCurrentToken == XmlPullParser.END_TAG) {
- mCurrentDepth--;
- }
-
- int token;
- try {
- token = peekNextExternalToken();
- consumeToken();
- } catch (EOFException e) {
- token = END_DOCUMENT;
- }
- switch (token) {
- case XmlPullParser.START_TAG:
- // We need to peek forward to find the next external token so
- // that we parse all pending INTERNAL_ATTRIBUTE tokens
- peekNextExternalToken();
- mCurrentDepth++;
- break;
- }
- mCurrentToken = token;
- return token;
- }
-
- /**
- * Peek at the next "external" token without consuming it.
- * <p>
- * External tokens, such as {@link #START_TAG}, are expected by typical
- * {@link XmlPullParser} clients. In contrast, internal tokens, such as
- * {@link #ATTRIBUTE}, are not expected by typical clients.
- * <p>
- * This method consumes any internal events until it reaches the next
- * external event.
- */
- private int peekNextExternalToken() throws IOException, XmlPullParserException {
- while (true) {
- final int token = peekNextToken();
- switch (token) {
- case ATTRIBUTE:
- consumeToken();
- continue;
- default:
- return token;
- }
- }
- }
-
- /**
- * Peek at the next token in the underlying stream without consuming it.
- */
- private int peekNextToken() throws IOException {
- return mIn.peekByte() & 0x0f;
- }
-
- /**
- * Parse and consume the next token in the underlying stream.
- */
- private void consumeToken() throws IOException, XmlPullParserException {
- final int event = mIn.readByte();
- final int token = event & 0x0f;
- final int type = event & 0xf0;
- switch (token) {
- case ATTRIBUTE: {
- final Attribute attr = obtainAttribute();
- attr.name = mIn.readInternedUTF();
- attr.type = type;
- switch (type) {
- case TYPE_NULL:
- case TYPE_BOOLEAN_TRUE:
- case TYPE_BOOLEAN_FALSE:
- // Nothing extra to fill in
- break;
- case TYPE_STRING:
- attr.valueString = mIn.readUTF();
- break;
- case TYPE_STRING_INTERNED:
- attr.valueString = mIn.readInternedUTF();
- break;
- case TYPE_BYTES_HEX:
- case TYPE_BYTES_BASE64:
- final int len = mIn.readUnsignedShort();
- final byte[] res = new byte[len];
- mIn.readFully(res);
- attr.valueBytes = res;
- break;
- case TYPE_INT:
- case TYPE_INT_HEX:
- attr.valueInt = mIn.readInt();
- break;
- case TYPE_LONG:
- case TYPE_LONG_HEX:
- attr.valueLong = mIn.readLong();
- break;
- case TYPE_FLOAT:
- attr.valueFloat = mIn.readFloat();
- break;
- case TYPE_DOUBLE:
- attr.valueDouble = mIn.readDouble();
- break;
- default:
- throw new IOException("Unexpected data type " + type);
- }
- break;
- }
- case XmlPullParser.START_DOCUMENT: {
- mCurrentName = null;
- mCurrentText = null;
- if (mAttributeCount > 0) resetAttributes();
- break;
- }
- case XmlPullParser.END_DOCUMENT: {
- mCurrentName = null;
- mCurrentText = null;
- if (mAttributeCount > 0) resetAttributes();
- break;
- }
- case XmlPullParser.START_TAG: {
- mCurrentName = mIn.readInternedUTF();
- mCurrentText = null;
- if (mAttributeCount > 0) resetAttributes();
- break;
- }
- case XmlPullParser.END_TAG: {
- mCurrentName = mIn.readInternedUTF();
- mCurrentText = null;
- if (mAttributeCount > 0) resetAttributes();
- break;
- }
- case XmlPullParser.TEXT:
- case XmlPullParser.CDSECT:
- case XmlPullParser.PROCESSING_INSTRUCTION:
- case XmlPullParser.COMMENT:
- case XmlPullParser.DOCDECL:
- case XmlPullParser.IGNORABLE_WHITESPACE: {
- mCurrentName = null;
- mCurrentText = mIn.readUTF();
- if (mAttributeCount > 0) resetAttributes();
- break;
- }
- case XmlPullParser.ENTITY_REF: {
- mCurrentName = mIn.readUTF();
- mCurrentText = resolveEntity(mCurrentName);
- if (mAttributeCount > 0) resetAttributes();
- break;
- }
- default: {
- throw new IOException("Unknown token " + token + " with type " + type);
- }
- }
- }
-
- /**
- * When the current tag is {@link #TEXT}, consume all subsequent "text"
- * events, as described by {@link #next}. When finished, the current event
- * will still be {@link #TEXT}.
- */
- private void consumeAdditionalText() throws IOException, XmlPullParserException {
- String combinedText = mCurrentText;
- while (true) {
- final int token = peekNextExternalToken();
- switch (token) {
- case COMMENT:
- case PROCESSING_INSTRUCTION:
- // Quietly consumed
- consumeToken();
- break;
- case TEXT:
- case CDSECT:
- case ENTITY_REF:
- // Additional text regions collected
- consumeToken();
- combinedText += mCurrentText;
- break;
- default:
- // Next token is something non-text, so wrap things up
- mCurrentToken = TEXT;
- mCurrentName = null;
- mCurrentText = combinedText;
- return;
- }
- }
- }
-
- static @NonNull String resolveEntity(@NonNull String entity)
- throws XmlPullParserException {
- switch (entity) {
- case "lt": return "<";
- case "gt": return ">";
- case "amp": return "&";
- case "apos": return "'";
- case "quot": return "\"";
- }
- if (entity.length() > 1 && entity.charAt(0) == '#') {
- final char c = (char) Integer.parseInt(entity.substring(1));
- return new String(new char[] { c });
- }
- throw new XmlPullParserException("Unknown entity " + entity);
- }
-
- @Override
- public void require(int type, String namespace, String name)
- throws XmlPullParserException, IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- if (mCurrentToken != type || !Objects.equals(mCurrentName, name)) {
- throw new XmlPullParserException(getPositionDescription());
- }
- }
-
- @Override
- public String nextText() throws XmlPullParserException, IOException {
- if (getEventType() != START_TAG) {
- throw new XmlPullParserException(getPositionDescription());
- }
- int eventType = next();
- if (eventType == TEXT) {
- String result = getText();
- eventType = next();
- if (eventType != END_TAG) {
- throw new XmlPullParserException(getPositionDescription());
- }
- return result;
- } else if (eventType == END_TAG) {
- return "";
- } else {
- throw new XmlPullParserException(getPositionDescription());
- }
- }
-
- @Override
- public int nextTag() throws XmlPullParserException, IOException {
- int eventType = next();
- if (eventType == TEXT && isWhitespace()) {
- eventType = next();
- }
- if (eventType != START_TAG && eventType != END_TAG) {
- throw new XmlPullParserException(getPositionDescription());
- }
- return eventType;
- }
-
- /**
- * Allocate and return a new {@link Attribute} associated with the tag being
- * currently processed. This will automatically grow the internal pool as
- * needed.
- */
- private @NonNull Attribute obtainAttribute() {
- if (mAttributeCount == mAttributes.length) {
- final int before = mAttributes.length;
- final int after = before + (before >> 1);
- mAttributes = Arrays.copyOf(mAttributes, after);
- for (int i = before; i < after; i++) {
- mAttributes[i] = new Attribute();
- }
- }
- return mAttributes[mAttributeCount++];
- }
-
- /**
- * Clear any {@link Attribute} instances that have been allocated by
- * {@link #obtainAttribute()}, returning them into the pool for recycling.
- */
- private void resetAttributes() {
- for (int i = 0; i < mAttributeCount; i++) {
- mAttributes[i].reset();
- }
- mAttributeCount = 0;
- }
-
- @Override
- public int getAttributeIndex(String namespace, String name) {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- for (int i = 0; i < mAttributeCount; i++) {
- if (Objects.equals(mAttributes[i].name, name)) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public String getAttributeValue(String namespace, String name) {
- final int index = getAttributeIndex(namespace, name);
- if (index != -1) {
- return mAttributes[index].getValueString();
- } else {
- return null;
- }
- }
-
- @Override
- public String getAttributeValue(int index) {
- return mAttributes[index].getValueString();
- }
-
- @Override
- public byte[] getAttributeBytesHex(int index) throws XmlPullParserException {
- return mAttributes[index].getValueBytesHex();
- }
-
- @Override
- public byte[] getAttributeBytesBase64(int index) throws XmlPullParserException {
- return mAttributes[index].getValueBytesBase64();
- }
-
- @Override
- public int getAttributeInt(int index) throws XmlPullParserException {
- return mAttributes[index].getValueInt();
- }
-
- @Override
- public int getAttributeIntHex(int index) throws XmlPullParserException {
- return mAttributes[index].getValueIntHex();
- }
-
- @Override
- public long getAttributeLong(int index) throws XmlPullParserException {
- return mAttributes[index].getValueLong();
- }
-
- @Override
- public long getAttributeLongHex(int index) throws XmlPullParserException {
- return mAttributes[index].getValueLongHex();
- }
-
- @Override
- public float getAttributeFloat(int index) throws XmlPullParserException {
- return mAttributes[index].getValueFloat();
- }
-
- @Override
- public double getAttributeDouble(int index) throws XmlPullParserException {
- return mAttributes[index].getValueDouble();
- }
-
- @Override
- public boolean getAttributeBoolean(int index) throws XmlPullParserException {
- return mAttributes[index].getValueBoolean();
- }
-
- @Override
- public String getText() {
- return mCurrentText;
- }
-
- @Override
- public char[] getTextCharacters(int[] holderForStartAndLength) {
- final char[] chars = mCurrentText.toCharArray();
- holderForStartAndLength[0] = 0;
- holderForStartAndLength[1] = chars.length;
- return chars;
- }
-
- @Override
- public String getInputEncoding() {
- return StandardCharsets.UTF_8.name();
- }
-
- @Override
- public int getDepth() {
- return mCurrentDepth;
- }
-
- @Override
- public String getPositionDescription() {
- // Not very helpful, but it's the best information we have
- return "Token " + mCurrentToken + " at depth " + mCurrentDepth;
- }
-
- @Override
- public int getLineNumber() {
- return -1;
- }
-
- @Override
- public int getColumnNumber() {
- return -1;
- }
-
- @Override
- public boolean isWhitespace() throws XmlPullParserException {
- switch (mCurrentToken) {
- case IGNORABLE_WHITESPACE:
- return true;
- case TEXT:
- case CDSECT:
- return !TextUtils.isGraphic(mCurrentText);
- default:
- throw new XmlPullParserException("Not applicable for token " + mCurrentToken);
- }
- }
-
- @Override
- public String getNamespace() {
- switch (mCurrentToken) {
- case START_TAG:
- case END_TAG:
- // Namespaces are unsupported
- return NO_NAMESPACE;
- default:
- return null;
- }
- }
-
- @Override
- public String getName() {
- return mCurrentName;
- }
-
- @Override
- public String getPrefix() {
- // Prefixes are not supported
- return null;
- }
-
- @Override
- public boolean isEmptyElementTag() throws XmlPullParserException {
- switch (mCurrentToken) {
- case START_TAG:
- try {
- return (peekNextExternalToken() == END_TAG);
- } catch (IOException e) {
- throw new XmlPullParserException(e.toString());
- }
- default:
- throw new XmlPullParserException("Not at START_TAG");
- }
- }
-
- @Override
- public int getAttributeCount() {
- return mAttributeCount;
- }
-
- @Override
- public String getAttributeNamespace(int index) {
- // Namespaces are unsupported
- return NO_NAMESPACE;
- }
-
- @Override
- public String getAttributeName(int index) {
- return mAttributes[index].name;
- }
-
- @Override
- public String getAttributePrefix(int index) {
- // Prefixes are not supported
- return null;
- }
-
- @Override
- public String getAttributeType(int index) {
- // Validation is not supported
- return "CDATA";
- }
-
- @Override
- public boolean isAttributeDefault(int index) {
- // Validation is not supported
- return false;
- }
-
- @Override
- public int getEventType() throws XmlPullParserException {
- return mCurrentToken;
- }
-
- @Override
- public int getNamespaceCount(int depth) throws XmlPullParserException {
- // Namespaces are unsupported
- return 0;
- }
-
- @Override
- public String getNamespacePrefix(int pos) throws XmlPullParserException {
- // Namespaces are unsupported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getNamespaceUri(int pos) throws XmlPullParserException {
- // Namespaces are unsupported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getNamespace(String prefix) {
- // Namespaces are unsupported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void defineEntityReplacementText(String entityName, String replacementText)
- throws XmlPullParserException {
- // Custom entities are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setFeature(String name, boolean state) throws XmlPullParserException {
- // Features are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean getFeature(String name) {
- // Features are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setProperty(String name, Object value) throws XmlPullParserException {
- // Properties are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object getProperty(String name) {
- // Properties are not supported
- throw new UnsupportedOperationException();
- }
-
- private static IllegalArgumentException illegalNamespace() {
- throw new IllegalArgumentException("Namespaces are not supported");
- }
-
- /**
- * Holder representing a single attribute. This design enables object
- * recycling without resorting to autoboxing.
- * <p>
- * To support conversion between human-readable XML and binary XML, the
- * various accessor methods will transparently convert from/to
- * human-readable values when needed.
- */
- private static class Attribute {
- public String name;
- public int type;
-
- public String valueString;
- public byte[] valueBytes;
- public int valueInt;
- public long valueLong;
- public float valueFloat;
- public double valueDouble;
-
- public void reset() {
- name = null;
- valueString = null;
- valueBytes = null;
- }
-
- public @Nullable String getValueString() {
- switch (type) {
- case TYPE_NULL:
- return null;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- return valueString;
- case TYPE_BYTES_HEX:
- return bytesToHexString(valueBytes);
- case TYPE_BYTES_BASE64:
- return Base64.encodeToString(valueBytes, Base64.NO_WRAP);
- case TYPE_INT:
- return Integer.toString(valueInt);
- case TYPE_INT_HEX:
- return Integer.toString(valueInt, 16);
- case TYPE_LONG:
- return Long.toString(valueLong);
- case TYPE_LONG_HEX:
- return Long.toString(valueLong, 16);
- case TYPE_FLOAT:
- return Float.toString(valueFloat);
- case TYPE_DOUBLE:
- return Double.toString(valueDouble);
- case TYPE_BOOLEAN_TRUE:
- return "true";
- case TYPE_BOOLEAN_FALSE:
- return "false";
- default:
- // Unknown data type; null is the best we can offer
- return null;
- }
- }
-
- public @Nullable byte[] getValueBytesHex() throws XmlPullParserException {
- switch (type) {
- case TYPE_NULL:
- return null;
- case TYPE_BYTES_HEX:
- case TYPE_BYTES_BASE64:
- return valueBytes;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return hexStringToBytes(valueString);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public @Nullable byte[] getValueBytesBase64() throws XmlPullParserException {
- switch (type) {
- case TYPE_NULL:
- return null;
- case TYPE_BYTES_HEX:
- case TYPE_BYTES_BASE64:
- return valueBytes;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Base64.decode(valueString, Base64.NO_WRAP);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public int getValueInt() throws XmlPullParserException {
- switch (type) {
- case TYPE_INT:
- case TYPE_INT_HEX:
- return valueInt;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Integer.parseInt(valueString);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public int getValueIntHex() throws XmlPullParserException {
- switch (type) {
- case TYPE_INT:
- case TYPE_INT_HEX:
- return valueInt;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Integer.parseInt(valueString, 16);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public long getValueLong() throws XmlPullParserException {
- switch (type) {
- case TYPE_LONG:
- case TYPE_LONG_HEX:
- return valueLong;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Long.parseLong(valueString);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public long getValueLongHex() throws XmlPullParserException {
- switch (type) {
- case TYPE_LONG:
- case TYPE_LONG_HEX:
- return valueLong;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Long.parseLong(valueString, 16);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public float getValueFloat() throws XmlPullParserException {
- switch (type) {
- case TYPE_FLOAT:
- return valueFloat;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Float.parseFloat(valueString);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public double getValueDouble() throws XmlPullParserException {
- switch (type) {
- case TYPE_DOUBLE:
- return valueDouble;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- try {
- return Double.parseDouble(valueString);
- } catch (Exception e) {
- throw new XmlPullParserException("Invalid attribute " + name + ": " + e);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
-
- public boolean getValueBoolean() throws XmlPullParserException {
- switch (type) {
- case TYPE_BOOLEAN_TRUE:
- return true;
- case TYPE_BOOLEAN_FALSE:
- return false;
- case TYPE_STRING:
- case TYPE_STRING_INTERNED:
- if ("true".equalsIgnoreCase(valueString)) {
- return true;
- } else if ("false".equalsIgnoreCase(valueString)) {
- return false;
- } else {
- throw new XmlPullParserException(
- "Invalid attribute " + name + ": " + valueString);
- }
- default:
- throw new XmlPullParserException("Invalid conversion from " + type);
- }
- }
- }
-
- // NOTE: To support unbundled clients, we include an inlined copy
- // of hex conversion logic from HexDump below
- private final static char[] HEX_DIGITS =
- { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- private static int toByte(char c) {
- if (c >= '0' && c <= '9') return (c - '0');
- if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
- if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
- throw new IllegalArgumentException("Invalid hex char '" + c + "'");
- }
-
- static String bytesToHexString(byte[] value) {
- final int length = value.length;
- final char[] buf = new char[length * 2];
- int bufIndex = 0;
- for (int i = 0; i < length; i++) {
- byte b = value[i];
- buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
- buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
- }
- return new String(buf);
- }
-
- static byte[] hexStringToBytes(String value) {
- final int length = value.length();
- if (length % 2 != 0) {
- throw new IllegalArgumentException("Invalid hex length " + length);
- }
- byte[] buffer = new byte[length / 2];
- for (int i = 0; i < length; i += 2) {
- buffer[i / 2] = (byte) ((toByte(value.charAt(i)) << 4)
- | toByte(value.charAt(i + 1)));
- }
- return buffer;
- }
-}
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
deleted file mode 100644
index 485430a..0000000
--- a/core/java/com/android/internal/util/BinaryXmlSerializer.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import static org.xmlpull.v1.XmlPullParser.CDSECT;
-import static org.xmlpull.v1.XmlPullParser.COMMENT;
-import static org.xmlpull.v1.XmlPullParser.DOCDECL;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.END_TAG;
-import static org.xmlpull.v1.XmlPullParser.ENTITY_REF;
-import static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE;
-import static org.xmlpull.v1.XmlPullParser.PROCESSING_INSTRUCTION;
-import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
-import static org.xmlpull.v1.XmlPullParser.TEXT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.TypedXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-
-/**
- * Serializer that writes XML documents using a custom binary wire protocol
- * which benchmarking has shown to be 4.3x faster and use 2.4x less disk space
- * than {@code Xml.newFastSerializer()} for a typical {@code packages.xml}.
- * <p>
- * The high-level design of the wire protocol is to directly serialize the event
- * stream, while efficiently and compactly writing strongly-typed primitives
- * delivered through the {@link TypedXmlSerializer} interface.
- * <p>
- * Each serialized event is a single byte where the lower half is a normal
- * {@link XmlPullParser} token and the upper half is an optional data type
- * signal, such as {@link #TYPE_INT}.
- * <p>
- * This serializer has some specific limitations:
- * <ul>
- * <li>Only the UTF-8 encoding is supported.
- * <li>Variable length values, such as {@code byte[]} or {@link String}, are
- * limited to 65,535 bytes in length. Note that {@link String} values are stored
- * as UTF-8 on the wire.
- * <li>Namespaces, prefixes, properties, and options are unsupported.
- * </ul>
- */
-public final class BinaryXmlSerializer implements TypedXmlSerializer {
- /**
- * The wire protocol always begins with a well-known magic value of
- * {@code ABX_}, representing "Android Binary XML." The final byte is a
- * version number which may be incremented as the protocol changes.
- */
- public static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
-
- /**
- * Internal token which represents an attribute associated with the most
- * recent {@link #START_TAG} token.
- */
- static final int ATTRIBUTE = 15;
-
- static final int TYPE_NULL = 1 << 4;
- static final int TYPE_STRING = 2 << 4;
- static final int TYPE_STRING_INTERNED = 3 << 4;
- static final int TYPE_BYTES_HEX = 4 << 4;
- static final int TYPE_BYTES_BASE64 = 5 << 4;
- static final int TYPE_INT = 6 << 4;
- static final int TYPE_INT_HEX = 7 << 4;
- static final int TYPE_LONG = 8 << 4;
- static final int TYPE_LONG_HEX = 9 << 4;
- static final int TYPE_FLOAT = 10 << 4;
- static final int TYPE_DOUBLE = 11 << 4;
- static final int TYPE_BOOLEAN_TRUE = 12 << 4;
- static final int TYPE_BOOLEAN_FALSE = 13 << 4;
-
- private FastDataOutput mOut;
-
- /**
- * Stack of tags which are currently active via {@link #startTag} and which
- * haven't been terminated via {@link #endTag}.
- */
- private int mTagCount = 0;
- private String[] mTagNames;
-
- /**
- * Write the given token and optional {@link String} into our buffer.
- */
- private void writeToken(int token, @Nullable String text) throws IOException {
- if (text != null) {
- mOut.writeByte(token | TYPE_STRING);
- mOut.writeUTF(text);
- } else {
- mOut.writeByte(token | TYPE_NULL);
- }
- }
-
- @Override
- public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException {
- if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
- throw new UnsupportedOperationException();
- }
-
- mOut = FastDataOutput.obtainUsing4ByteSequences(os);
- mOut.write(PROTOCOL_MAGIC_VERSION_0);
-
- mTagCount = 0;
- mTagNames = new String[8];
- }
-
- @Override
- public void setOutput(Writer writer) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void flush() throws IOException {
- if (mOut != null) {
- mOut.flush();
- }
- }
-
- @Override
- public void startDocument(@Nullable String encoding, @Nullable Boolean standalone)
- throws IOException {
- if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
- throw new UnsupportedOperationException();
- }
- if (standalone != null && !standalone) {
- throw new UnsupportedOperationException();
- }
- mOut.writeByte(START_DOCUMENT | TYPE_NULL);
- }
-
- @Override
- public void endDocument() throws IOException {
- mOut.writeByte(END_DOCUMENT | TYPE_NULL);
- flush();
-
- mOut.release();
- mOut = null;
- }
-
- @Override
- public int getDepth() {
- return mTagCount;
- }
-
- @Override
- public String getNamespace() {
- // Namespaces are unsupported
- return XmlPullParser.NO_NAMESPACE;
- }
-
- @Override
- public String getName() {
- return mTagNames[mTagCount - 1];
- }
-
- @Override
- public XmlSerializer startTag(String namespace, String name) throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- if (mTagCount == mTagNames.length) {
- mTagNames = Arrays.copyOf(mTagNames, mTagCount + (mTagCount >> 1));
- }
- mTagNames[mTagCount++] = name;
- mOut.writeByte(START_TAG | TYPE_STRING_INTERNED);
- mOut.writeInternedUTF(name);
- return this;
- }
-
- @Override
- public XmlSerializer endTag(String namespace, String name) throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mTagCount--;
- mOut.writeByte(END_TAG | TYPE_STRING_INTERNED);
- mOut.writeInternedUTF(name);
- return this;
- }
-
- @Override
- public XmlSerializer attribute(String namespace, String name, String value) throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_STRING);
- mOut.writeInternedUTF(name);
- mOut.writeUTF(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeInterned(String namespace, String name, String value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_STRING_INTERNED);
- mOut.writeInternedUTF(name);
- mOut.writeInternedUTF(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_BYTES_HEX);
- mOut.writeInternedUTF(name);
- mOut.writeShort(value.length);
- mOut.write(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64);
- mOut.writeInternedUTF(name);
- mOut.writeShort(value.length);
- mOut.write(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeInt(String namespace, String name, int value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_INT);
- mOut.writeInternedUTF(name);
- mOut.writeInt(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeIntHex(String namespace, String name, int value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_INT_HEX);
- mOut.writeInternedUTF(name);
- mOut.writeInt(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeLong(String namespace, String name, long value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_LONG);
- mOut.writeInternedUTF(name);
- mOut.writeLong(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeLongHex(String namespace, String name, long value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_LONG_HEX);
- mOut.writeInternedUTF(name);
- mOut.writeLong(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeFloat(String namespace, String name, float value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_FLOAT);
- mOut.writeInternedUTF(name);
- mOut.writeFloat(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeDouble(String namespace, String name, double value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- mOut.writeByte(ATTRIBUTE | TYPE_DOUBLE);
- mOut.writeInternedUTF(name);
- mOut.writeDouble(value);
- return this;
- }
-
- @Override
- public XmlSerializer attributeBoolean(String namespace, String name, boolean value)
- throws IOException {
- if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
- if (value) {
- mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_TRUE);
- mOut.writeInternedUTF(name);
- } else {
- mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_FALSE);
- mOut.writeInternedUTF(name);
- }
- return this;
- }
-
- @Override
- public XmlSerializer text(char[] buf, int start, int len) throws IOException {
- writeToken(TEXT, new String(buf, start, len));
- return this;
- }
-
- @Override
- public XmlSerializer text(String text) throws IOException {
- writeToken(TEXT, text);
- return this;
- }
-
- @Override
- public void cdsect(String text) throws IOException {
- writeToken(CDSECT, text);
- }
-
- @Override
- public void entityRef(String text) throws IOException {
- writeToken(ENTITY_REF, text);
- }
-
- @Override
- public void processingInstruction(String text) throws IOException {
- writeToken(PROCESSING_INSTRUCTION, text);
- }
-
- @Override
- public void comment(String text) throws IOException {
- writeToken(COMMENT, text);
- }
-
- @Override
- public void docdecl(String text) throws IOException {
- writeToken(DOCDECL, text);
- }
-
- @Override
- public void ignorableWhitespace(String text) throws IOException {
- writeToken(IGNORABLE_WHITESPACE, text);
- }
-
- @Override
- public void setFeature(String name, boolean state) {
- // Quietly handle no-op features
- if ("http://xmlpull.org/v1/doc/features.html#indent-output".equals(name)) {
- return;
- }
- // Features are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean getFeature(String name) {
- // Features are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setProperty(String name, Object value) {
- // Properties are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object getProperty(String name) {
- // Properties are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setPrefix(String prefix, String namespace) {
- // Prefixes are not supported
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getPrefix(String namespace, boolean generatePrefix) {
- // Prefixes are not supported
- throw new UnsupportedOperationException();
- }
-
- private static IllegalArgumentException illegalNamespace() {
- throw new IllegalArgumentException("Namespaces are not supported");
- }
-}
diff --git a/core/java/com/android/internal/util/FastDataInput.java b/core/java/com/android/internal/util/FastDataInput.java
deleted file mode 100644
index 5117034..0000000
--- a/core/java/com/android/internal/util/FastDataInput.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.annotation.NonNull;
-import android.util.CharsetUtils;
-
-import dalvik.system.VMRuntime;
-
-import java.io.BufferedInputStream;
-import java.io.Closeable;
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Optimized implementation of {@link DataInput} which buffers data in memory
- * from the underlying {@link InputStream}.
- * <p>
- * Benchmarks have demonstrated this class is 3x more efficient than using a
- * {@link DataInputStream} with a {@link BufferedInputStream}.
- */
-public class FastDataInput implements DataInput, Closeable {
- private static final int MAX_UNSIGNED_SHORT = 65_535;
-
- private static final int DEFAULT_BUFFER_SIZE = 32_768;
-
- private static AtomicReference<FastDataInput> sInCache = new AtomicReference<>();
-
- private final VMRuntime mRuntime;
-
- private final byte[] mBuffer;
- private final long mBufferPtr;
- private final int mBufferCap;
- private final boolean mUse4ByteSequence;
-
- private InputStream mIn;
- private int mBufferPos;
- private int mBufferLim;
-
- /**
- * Values that have been "interned" by {@link #readInternedUTF()}.
- */
- private int mStringRefCount = 0;
- private String[] mStringRefs = new String[32];
-
- /**
- * @deprecated callers must specify {@code use4ByteSequence} so they make a
- * clear choice about working around a long-standing ART bug, as
- * described by the {@code kUtfUse4ByteSequence} comments in
- * {@code art/runtime/jni/jni_internal.cc}.
- */
- @Deprecated
- public FastDataInput(@NonNull InputStream in, int bufferSize) {
- this(in, bufferSize, true /* use4ByteSequence */);
- }
-
- public FastDataInput(@NonNull InputStream in, int bufferSize, boolean use4ByteSequence) {
- mRuntime = VMRuntime.getRuntime();
- mIn = Objects.requireNonNull(in);
- if (bufferSize < 8) {
- throw new IllegalArgumentException();
- }
-
- mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);
- mBufferPtr = mRuntime.addressOf(mBuffer);
- mBufferCap = mBuffer.length;
- mUse4ByteSequence = use4ByteSequence;
- }
-
- /**
- * Obtain a {@link FastDataInput} configured with the given
- * {@link InputStream} and which encodes large code-points using 3-byte
- * sequences.
- * <p>
- * This <em>is</em> compatible with the {@link DataInput} API contract,
- * which specifies that large code-points must be encoded with 3-byte
- * sequences.
- */
- public static FastDataInput obtainUsing3ByteSequences(@NonNull InputStream in) {
- return new FastDataInput(in, DEFAULT_BUFFER_SIZE, false /* use4ByteSequence */);
- }
-
- /**
- * Obtain a {@link FastDataInput} configured with the given
- * {@link InputStream} and which decodes large code-points using 4-byte
- * sequences.
- * <p>
- * This <em>is not</em> compatible with the {@link DataInput} API contract,
- * which specifies that large code-points must be encoded with 3-byte
- * sequences.
- */
- public static FastDataInput obtainUsing4ByteSequences(@NonNull InputStream in) {
- FastDataInput instance = sInCache.getAndSet(null);
- if (instance != null) {
- instance.setInput(in);
- return instance;
- }
- return new FastDataInput(in, DEFAULT_BUFFER_SIZE, true /* use4ByteSequence */);
- }
-
- /**
- * Release a {@link FastDataInput} to potentially be recycled. You must not
- * interact with the object after releasing it.
- */
- public void release() {
- mIn = null;
- mBufferPos = 0;
- mBufferLim = 0;
- mStringRefCount = 0;
-
- if (mBufferCap == DEFAULT_BUFFER_SIZE && mUse4ByteSequence) {
- // Try to return to the cache.
- sInCache.compareAndSet(null, this);
- }
- }
-
- /**
- * Re-initializes the object for the new input.
- */
- private void setInput(@NonNull InputStream in) {
- mIn = Objects.requireNonNull(in);
- mBufferPos = 0;
- mBufferLim = 0;
- mStringRefCount = 0;
- }
-
- private void fill(int need) throws IOException {
- final int remain = mBufferLim - mBufferPos;
- System.arraycopy(mBuffer, mBufferPos, mBuffer, 0, remain);
- mBufferPos = 0;
- mBufferLim = remain;
- need -= remain;
-
- while (need > 0) {
- int c = mIn.read(mBuffer, mBufferLim, mBufferCap - mBufferLim);
- if (c == -1) {
- throw new EOFException();
- } else {
- mBufferLim += c;
- need -= c;
- }
- }
- }
-
- @Override
- public void close() throws IOException {
- mIn.close();
- release();
- }
-
- @Override
- public void readFully(byte[] b) throws IOException {
- readFully(b, 0, b.length);
- }
-
- @Override
- public void readFully(byte[] b, int off, int len) throws IOException {
- // Attempt to read directly from buffer space if there's enough room,
- // otherwise fall back to chunking into place
- if (mBufferCap >= len) {
- if (mBufferLim - mBufferPos < len) fill(len);
- System.arraycopy(mBuffer, mBufferPos, b, off, len);
- mBufferPos += len;
- } else {
- final int remain = mBufferLim - mBufferPos;
- System.arraycopy(mBuffer, mBufferPos, b, off, remain);
- mBufferPos += remain;
- off += remain;
- len -= remain;
-
- while (len > 0) {
- int c = mIn.read(b, off, len);
- if (c == -1) {
- throw new EOFException();
- } else {
- off += c;
- len -= c;
- }
- }
- }
- }
-
- @Override
- public String readUTF() throws IOException {
- if (mUse4ByteSequence) {
- return readUTFUsing4ByteSequences();
- } else {
- return readUTFUsing3ByteSequences();
- }
- }
-
- private String readUTFUsing4ByteSequences() throws IOException {
- // Attempt to read directly from buffer space if there's enough room,
- // otherwise fall back to chunking into place
- final int len = readUnsignedShort();
- if (mBufferCap > len) {
- if (mBufferLim - mBufferPos < len) fill(len);
- final String res = CharsetUtils.fromModifiedUtf8Bytes(mBufferPtr, mBufferPos, len);
- mBufferPos += len;
- return res;
- } else {
- final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
- readFully(tmp, 0, len);
- return CharsetUtils.fromModifiedUtf8Bytes(mRuntime.addressOf(tmp), 0, len);
- }
- }
-
- private String readUTFUsing3ByteSequences() throws IOException {
- // Attempt to read directly from buffer space if there's enough room,
- // otherwise fall back to chunking into place
- final int len = readUnsignedShort();
- if (mBufferCap > len) {
- if (mBufferLim - mBufferPos < len) fill(len);
- final String res = ModifiedUtf8.decode(mBuffer, new char[len], mBufferPos, len);
- mBufferPos += len;
- return res;
- } else {
- final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
- readFully(tmp, 0, len);
- return ModifiedUtf8.decode(tmp, new char[len], 0, len);
- }
- }
-
- /**
- * Read a {@link String} value with the additional signal that the given
- * value is a candidate for being canonicalized, similar to
- * {@link String#intern()}.
- * <p>
- * Canonicalization is implemented by writing each unique string value once
- * the first time it appears, and then writing a lightweight {@code short}
- * reference when that string is written again in the future.
- *
- * @see FastDataOutput#writeInternedUTF(String)
- */
- public @NonNull String readInternedUTF() throws IOException {
- final int ref = readUnsignedShort();
- if (ref == MAX_UNSIGNED_SHORT) {
- final String s = readUTF();
-
- // We can only safely intern when we have remaining values; if we're
- // full we at least sent the string value above
- if (mStringRefCount < MAX_UNSIGNED_SHORT) {
- if (mStringRefCount == mStringRefs.length) {
- mStringRefs = Arrays.copyOf(mStringRefs,
- mStringRefCount + (mStringRefCount >> 1));
- }
- mStringRefs[mStringRefCount++] = s;
- }
-
- return s;
- } else {
- return mStringRefs[ref];
- }
- }
-
- @Override
- public boolean readBoolean() throws IOException {
- return readByte() != 0;
- }
-
- /**
- * Returns the same decoded value as {@link #readByte()} but without
- * actually consuming the underlying data.
- */
- public byte peekByte() throws IOException {
- if (mBufferLim - mBufferPos < 1) fill(1);
- return mBuffer[mBufferPos];
- }
-
- @Override
- public byte readByte() throws IOException {
- if (mBufferLim - mBufferPos < 1) fill(1);
- return mBuffer[mBufferPos++];
- }
-
- @Override
- public int readUnsignedByte() throws IOException {
- return Byte.toUnsignedInt(readByte());
- }
-
- @Override
- public short readShort() throws IOException {
- if (mBufferLim - mBufferPos < 2) fill(2);
- return (short) (((mBuffer[mBufferPos++] & 0xff) << 8) |
- ((mBuffer[mBufferPos++] & 0xff) << 0));
- }
-
- @Override
- public int readUnsignedShort() throws IOException {
- return Short.toUnsignedInt((short) readShort());
- }
-
- @Override
- public char readChar() throws IOException {
- return (char) readShort();
- }
-
- @Override
- public int readInt() throws IOException {
- if (mBufferLim - mBufferPos < 4) fill(4);
- return (((mBuffer[mBufferPos++] & 0xff) << 24) |
- ((mBuffer[mBufferPos++] & 0xff) << 16) |
- ((mBuffer[mBufferPos++] & 0xff) << 8) |
- ((mBuffer[mBufferPos++] & 0xff) << 0));
- }
-
- @Override
- public long readLong() throws IOException {
- if (mBufferLim - mBufferPos < 8) fill(8);
- int h = ((mBuffer[mBufferPos++] & 0xff) << 24) |
- ((mBuffer[mBufferPos++] & 0xff) << 16) |
- ((mBuffer[mBufferPos++] & 0xff) << 8) |
- ((mBuffer[mBufferPos++] & 0xff) << 0);
- int l = ((mBuffer[mBufferPos++] & 0xff) << 24) |
- ((mBuffer[mBufferPos++] & 0xff) << 16) |
- ((mBuffer[mBufferPos++] & 0xff) << 8) |
- ((mBuffer[mBufferPos++] & 0xff) << 0);
- return (((long) h) << 32L) | ((long) l) & 0xffffffffL;
- }
-
- @Override
- public float readFloat() throws IOException {
- return Float.intBitsToFloat(readInt());
- }
-
- @Override
- public double readDouble() throws IOException {
- return Double.longBitsToDouble(readLong());
- }
-
- @Override
- public int skipBytes(int n) throws IOException {
- // Callers should read data piecemeal
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String readLine() throws IOException {
- // Callers should read data piecemeal
- throw new UnsupportedOperationException();
- }
-}
diff --git a/core/java/com/android/internal/util/FastDataOutput.java b/core/java/com/android/internal/util/FastDataOutput.java
deleted file mode 100644
index 5b6075e..0000000
--- a/core/java/com/android/internal/util/FastDataOutput.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.annotation.NonNull;
-import android.util.CharsetUtils;
-
-import dalvik.system.VMRuntime;
-
-import java.io.BufferedOutputStream;
-import java.io.Closeable;
-import java.io.DataOutput;
-import java.io.DataOutputStream;
-import java.io.Flushable;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.HashMap;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Optimized implementation of {@link DataOutput} which buffers data in memory
- * before flushing to the underlying {@link OutputStream}.
- * <p>
- * Benchmarks have demonstrated this class is 2x more efficient than using a
- * {@link DataOutputStream} with a {@link BufferedOutputStream}.
- */
-public class FastDataOutput implements DataOutput, Flushable, Closeable {
- private static final int MAX_UNSIGNED_SHORT = 65_535;
-
- private static final int DEFAULT_BUFFER_SIZE = 32_768;
-
- private static AtomicReference<FastDataOutput> sOutCache = new AtomicReference<>();
-
- private final VMRuntime mRuntime;
-
- private final byte[] mBuffer;
- private final long mBufferPtr;
- private final int mBufferCap;
- private final boolean mUse4ByteSequence;
-
- private OutputStream mOut;
- private int mBufferPos;
-
- /**
- * Values that have been "interned" by {@link #writeInternedUTF(String)}.
- */
- private final HashMap<String, Integer> mStringRefs = new HashMap<>();
-
- /**
- * @deprecated callers must specify {@code use4ByteSequence} so they make a
- * clear choice about working around a long-standing ART bug, as
- * described by the {@code kUtfUse4ByteSequence} comments in
- * {@code art/runtime/jni/jni_internal.cc}.
- */
- @Deprecated
- public FastDataOutput(@NonNull OutputStream out, int bufferSize) {
- this(out, bufferSize, true /* use4ByteSequence */);
- }
-
- public FastDataOutput(@NonNull OutputStream out, int bufferSize, boolean use4ByteSequence) {
- mRuntime = VMRuntime.getRuntime();
- if (bufferSize < 8) {
- throw new IllegalArgumentException();
- }
-
- mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);
- mBufferPtr = mRuntime.addressOf(mBuffer);
- mBufferCap = mBuffer.length;
- mUse4ByteSequence = use4ByteSequence;
-
- setOutput(out);
- }
-
- /**
- * Obtain a {@link FastDataOutput} configured with the given
- * {@link OutputStream} and which encodes large code-points using 3-byte
- * sequences.
- * <p>
- * This <em>is</em> compatible with the {@link DataOutput} API contract,
- * which specifies that large code-points must be encoded with 3-byte
- * sequences.
- */
- public static FastDataOutput obtainUsing3ByteSequences(@NonNull OutputStream out) {
- return new FastDataOutput(out, DEFAULT_BUFFER_SIZE, false /* use4ByteSequence */);
- }
-
- /**
- * Obtain a {@link FastDataOutput} configured with the given
- * {@link OutputStream} and which encodes large code-points using 4-byte
- * sequences.
- * <p>
- * This <em>is not</em> compatible with the {@link DataOutput} API contract,
- * which specifies that large code-points must be encoded with 3-byte
- * sequences.
- */
- public static FastDataOutput obtainUsing4ByteSequences(@NonNull OutputStream out) {
- FastDataOutput instance = sOutCache.getAndSet(null);
- if (instance != null) {
- instance.setOutput(out);
- return instance;
- }
- return new FastDataOutput(out, DEFAULT_BUFFER_SIZE, true /* use4ByteSequence */);
- }
-
- /**
- * Release a {@link FastDataOutput} to potentially be recycled. You must not
- * interact with the object after releasing it.
- */
- public void release() {
- if (mBufferPos > 0) {
- throw new IllegalStateException("Lingering data, call flush() before releasing.");
- }
-
- mOut = null;
- mBufferPos = 0;
- mStringRefs.clear();
-
- if (mBufferCap == DEFAULT_BUFFER_SIZE && mUse4ByteSequence) {
- // Try to return to the cache.
- sOutCache.compareAndSet(null, this);
- }
- }
-
- /**
- * Re-initializes the object for the new output.
- */
- private void setOutput(@NonNull OutputStream out) {
- mOut = Objects.requireNonNull(out);
- mBufferPos = 0;
- mStringRefs.clear();
- }
-
- private void drain() throws IOException {
- if (mBufferPos > 0) {
- mOut.write(mBuffer, 0, mBufferPos);
- mBufferPos = 0;
- }
- }
-
- @Override
- public void flush() throws IOException {
- drain();
- mOut.flush();
- }
-
- @Override
- public void close() throws IOException {
- mOut.close();
- release();
- }
-
- @Override
- public void write(int b) throws IOException {
- writeByte(b);
- }
-
- @Override
- public void write(byte[] b) throws IOException {
- write(b, 0, b.length);
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- if (mBufferCap < len) {
- drain();
- mOut.write(b, off, len);
- } else {
- if (mBufferCap - mBufferPos < len) drain();
- System.arraycopy(b, off, mBuffer, mBufferPos, len);
- mBufferPos += len;
- }
- }
-
- @Override
- public void writeUTF(String s) throws IOException {
- if (mUse4ByteSequence) {
- writeUTFUsing4ByteSequences(s);
- } else {
- writeUTFUsing3ByteSequences(s);
- }
- }
-
- private void writeUTFUsing4ByteSequences(String s) throws IOException {
- // Attempt to write directly to buffer space if there's enough room,
- // otherwise fall back to chunking into place
- if (mBufferCap - mBufferPos < 2 + s.length()) drain();
-
- // Magnitude of this returned value indicates the number of bytes
- // required to encode the string; sign indicates success/failure
- int len = CharsetUtils.toModifiedUtf8Bytes(s, mBufferPtr, mBufferPos + 2, mBufferCap);
- if (Math.abs(len) > MAX_UNSIGNED_SHORT) {
- throw new IOException("Modified UTF-8 length too large: " + len);
- }
-
- if (len >= 0) {
- // Positive value indicates the string was encoded into the buffer
- // successfully, so we only need to prefix with length
- writeShort(len);
- mBufferPos += len;
- } else {
- // Negative value indicates buffer was too small and we need to
- // allocate a temporary buffer for encoding
- len = -len;
- final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
- CharsetUtils.toModifiedUtf8Bytes(s, mRuntime.addressOf(tmp), 0, tmp.length);
- writeShort(len);
- write(tmp, 0, len);
- }
- }
-
- private void writeUTFUsing3ByteSequences(String s) throws IOException {
- final int len = (int) ModifiedUtf8.countBytes(s, false);
- if (len > MAX_UNSIGNED_SHORT) {
- throw new IOException("Modified UTF-8 length too large: " + len);
- }
-
- // Attempt to write directly to buffer space if there's enough room,
- // otherwise fall back to chunking into place
- if (mBufferCap >= 2 + len) {
- if (mBufferCap - mBufferPos < 2 + len) drain();
- writeShort(len);
- ModifiedUtf8.encode(mBuffer, mBufferPos, s);
- mBufferPos += len;
- } else {
- final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
- ModifiedUtf8.encode(tmp, 0, s);
- writeShort(len);
- write(tmp, 0, len);
- }
- }
-
- /**
- * Write a {@link String} value with the additional signal that the given
- * value is a candidate for being canonicalized, similar to
- * {@link String#intern()}.
- * <p>
- * Canonicalization is implemented by writing each unique string value once
- * the first time it appears, and then writing a lightweight {@code short}
- * reference when that string is written again in the future.
- *
- * @see FastDataInput#readInternedUTF()
- */
- public void writeInternedUTF(@NonNull String s) throws IOException {
- Integer ref = mStringRefs.get(s);
- if (ref != null) {
- writeShort(ref);
- } else {
- writeShort(MAX_UNSIGNED_SHORT);
- writeUTF(s);
-
- // We can only safely intern when we have remaining values; if we're
- // full we at least sent the string value above
- ref = mStringRefs.size();
- if (ref < MAX_UNSIGNED_SHORT) {
- mStringRefs.put(s, ref);
- }
- }
- }
-
- @Override
- public void writeBoolean(boolean v) throws IOException {
- writeByte(v ? 1 : 0);
- }
-
- @Override
- public void writeByte(int v) throws IOException {
- if (mBufferCap - mBufferPos < 1) drain();
- mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff);
- }
-
- @Override
- public void writeShort(int v) throws IOException {
- if (mBufferCap - mBufferPos < 2) drain();
- mBuffer[mBufferPos++] = (byte) ((v >> 8) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff);
- }
-
- @Override
- public void writeChar(int v) throws IOException {
- writeShort((short) v);
- }
-
- @Override
- public void writeInt(int v) throws IOException {
- if (mBufferCap - mBufferPos < 4) drain();
- mBuffer[mBufferPos++] = (byte) ((v >> 24) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((v >> 16) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((v >> 8) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff);
- }
-
- @Override
- public void writeLong(long v) throws IOException {
- if (mBufferCap - mBufferPos < 8) drain();
- int i = (int) (v >> 32);
- mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((i >> 8) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((i >> 0) & 0xff);
- i = (int) v;
- mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((i >> 8) & 0xff);
- mBuffer[mBufferPos++] = (byte) ((i >> 0) & 0xff);
- }
-
- @Override
- public void writeFloat(float v) throws IOException {
- writeInt(Float.floatToIntBits(v));
- }
-
- @Override
- public void writeDouble(double v) throws IOException {
- writeLong(Double.doubleToLongBits(v));
- }
-
- @Override
- public void writeBytes(String s) throws IOException {
- // Callers should use writeUTF()
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void writeChars(String s) throws IOException {
- // Callers should use writeUTF()
- throw new UnsupportedOperationException();
- }
-}
diff --git a/core/java/com/android/internal/util/ModifiedUtf8.java b/core/java/com/android/internal/util/ModifiedUtf8.java
deleted file mode 100644
index a144c00..0000000
--- a/core/java/com/android/internal/util/ModifiedUtf8.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.util;
-
-import java.io.UTFDataFormatException;
-
-public class ModifiedUtf8 {
- /**
- * Decodes a byte array containing <i>modified UTF-8</i> bytes into a string.
- *
- * <p>Note that although this method decodes the (supposedly impossible) zero byte to U+0000,
- * that's what the RI does too.
- */
- public static String decode(byte[] in, char[] out, int offset, int utfSize)
- throws UTFDataFormatException {
- int count = 0, s = 0, a;
- while (count < utfSize) {
- if ((out[s] = (char) in[offset + count++]) < '\u0080') {
- s++;
- } else if (((a = out[s]) & 0xe0) == 0xc0) {
- if (count >= utfSize) {
- throw new UTFDataFormatException("bad second byte at " + count);
- }
- int b = in[offset + count++];
- if ((b & 0xC0) != 0x80) {
- throw new UTFDataFormatException("bad second byte at " + (count - 1));
- }
- out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
- } else if ((a & 0xf0) == 0xe0) {
- if (count + 1 >= utfSize) {
- throw new UTFDataFormatException("bad third byte at " + (count + 1));
- }
- int b = in[offset + count++];
- int c = in[offset + count++];
- if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
- throw new UTFDataFormatException("bad second or third byte at " + (count - 2));
- }
- out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
- } else {
- throw new UTFDataFormatException("bad byte at " + (count - 1));
- }
- }
- return new String(out, 0, s);
- }
-
- /**
- * Returns the number of bytes the modified UTF-8 representation of 's' would take. Note
- * that this is just the space for the bytes representing the characters, not the length
- * which precedes those bytes, because different callers represent the length differently,
- * as two, four, or even eight bytes. If {@code shortLength} is true, we'll throw an
- * exception if the string is too long for its length to be represented by a short.
- */
- public static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
- long result = 0;
- final int length = s.length();
- for (int i = 0; i < length; ++i) {
- char ch = s.charAt(i);
- if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
- ++result;
- } else if (ch <= 2047) {
- result += 2;
- } else {
- result += 3;
- }
- if (shortLength && result > 65535) {
- throw new UTFDataFormatException("String more than 65535 UTF bytes long");
- }
- }
- return result;
- }
-
- /**
- * Encodes the <i>modified UTF-8</i> bytes corresponding to string {@code s} into the
- * byte array {@code dst}, starting at the given {@code offset}.
- */
- public static void encode(byte[] dst, int offset, String s) {
- final int length = s.length();
- for (int i = 0; i < length; i++) {
- char ch = s.charAt(i);
- if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
- dst[offset++] = (byte) ch;
- } else if (ch <= 2047) {
- dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6)));
- dst[offset++] = (byte) (0x80 | (0x3f & ch));
- } else {
- dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12)));
- dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6)));
- dst[offset++] = (byte) (0x80 | (0x3f & ch));
- }
- }
- }
-
- private ModifiedUtf8() {
- }
-}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index de6b65f3..af5e3b3 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -25,10 +25,11 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Base64;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import libcore.util.HexEncoding;
import org.xmlpull.v1.XmlPullParser;
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 16b9f00..343e9d8 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -153,6 +153,11 @@
return result;
}
+static jboolean android_view_VelocityTracker_nativeIsAxisSupported(JNIEnv* env, jclass clazz,
+ jint axis) {
+ return VelocityTracker::isAxisSupported(axis);
+}
+
// --- JNI Registration ---
static const JNINativeMethod gVelocityTrackerMethods[] = {
@@ -167,6 +172,8 @@
{"nativeGetVelocity", "(JII)F", (void*)android_view_VelocityTracker_nativeGetVelocity},
{"nativeGetEstimator", "(JIILandroid/view/VelocityTracker$Estimator;)Z",
(void*)android_view_VelocityTracker_nativeGetEstimator},
+ {"nativeIsAxisSupported", "(I)Z",
+ (void*)android_view_VelocityTracker_nativeIsAxisSupported},
};
int register_android_view_VelocityTracker(JNIEnv* env) {
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4b9abad..0ebce40 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Snelsluit"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nuwe kennisgewing"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuele sleutelbord"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fisieke sleutelbord"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sekuriteit"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Motormodus"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b6fdcdf..a861f3c 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"መቆለፊያ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"አዲስ ማሳወቂያ"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ምናባዊ የቁልፍ ሰሌዳ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"አካላዊ ቁልፍ ሰሌዳ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ደህንነት"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"የመኪና ሁነታ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 977cf8e..7623fb1 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -268,7 +268,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"إلغاء التأمين"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"إشعار جديد"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"لوحة المفاتيح الافتراضية"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"لوحة المفاتيح الخارجية"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"الأمان"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"وضع السيارة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index dbce595..3a97baf 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"লকডাউন"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"৯৯৯+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"নতুন জাননী"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ভাৰ্শ্বুৱল কীব\'ৰ্ড"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"কায়িক কীব’ৰ্ড"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"সুৰক্ষা"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"গাড়ী ম\'ড"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 586adef..0b361ac 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Kilidləyin"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Yeni bildiriş"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual klaviatura"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fiziki klaviatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Güvənlik"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Avtomobil rejimi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index c19338d..078c098 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Zaključavanje"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Novo obaveštenje"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuelna tastatura"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizička tastatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Bezbednost"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Režim rada u automobilu"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index ab338c7..023e82c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Блакіроўка"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Новае апавяшчэнне"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Віртуальная клавіятура"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Фізічная клавіятура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Бяспека"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Рэжым \"У машыне\""</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 46ab1ad..aaa080a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Заключване"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ново известие"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуална клавиатура"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физическа клавиатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Сигурност"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Моторежим"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ed77eef..ee1db8e 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"লকডাউন"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"৯৯৯+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"নতুন বিজ্ঞপ্তি"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ভার্চুয়াল কীবোর্ড"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ফিজিক্যাল কীবোর্ড"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"নিরাপত্তা"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"গাড়ি মোড"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 081d8f2..20f6bc1 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Zaključavanje"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Novo obavještenje"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuelna tastatura"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizička tastatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sigurnost"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Način rada u automobilu"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index aad5668..2142b60 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueig de seguretat"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"+999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificació nova"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclat virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclat físic"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguretat"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Mode de cotxe"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e9d5ab2..7720d08 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Zamknuto"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nové oznámení"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuální klávesnice"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyzická klávesnice"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Zabezpečení"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Režim Auto"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index edb962c..ecd6407 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lås enhed"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ny notifikation"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuelt tastatur"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysisk tastatur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sikkerhed"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Biltilstand"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b7a0b02..3d5985c9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Sperren"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Neue Benachrichtigung"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Bildschirmtastatur"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physische Tastatur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sicherheit"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Automodus"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a9dd1cf..f84a9fb 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Κλείδωμα"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Νέα ειδοποίηση"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Εικονικό πληκτρολόγιο"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Κανονικό πληκτρολόγιο"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Ασφάλεια"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Λειτουργία αυτοκινήτου"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 1cc8d50..4c0510b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual keyboard"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Car mode"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 6fa02f3..875ddf9 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual keyboard"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Car mode"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fac706e..6e034b7 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual keyboard"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Car mode"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 55c121ac..643f27f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual keyboard"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Car mode"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 1b190e3..91e99ff 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual keyboard"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Car mode"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 106935c2..6a45205 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguridad"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modo auto"</string>
@@ -1970,8 +1969,8 @@
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Presiona para ver archivos"</string>
<string name="pin_target" msgid="8036028973110156895">"Fijar"</string>
<string name="pin_specific_target" msgid="7824671240625957415">"Fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="unpin_target" msgid="3963318576590204447">"No fijar"</string>
- <string name="unpin_specific_target" msgid="3859828252160908146">"No fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="unpin_target" msgid="3963318576590204447">"Dejar de fijar"</string>
+ <string name="unpin_specific_target" msgid="3859828252160908146">"Dejar de fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Información de apps"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3ae013b..66f67b3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo de seguridad"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"> 999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguridad"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modo de coche"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 182aa65..349a6b2 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lukustamine"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Uus märguanne"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuaalne klaviatuur"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Füüsiline klaviatuur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Turvalisus"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Autorežiim"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 31cc0b6..d4759d5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Blokeoa"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Jakinarazpen berria"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teklatu birtuala"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teklatu fisikoa"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurtasuna"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Auto modua"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 58a7f62..4064353 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"قفل همه"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"۹۹۹+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"اعلان جدید"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"صفحهکلید مجازی"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"صفحهکلید فیزیکی"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"امنیت"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"حالت خودرو"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 31d2571..8fedfb7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lukitse"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Uusi ilmoitus"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuaalinen näppäimistö"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyysinen näppäimistö"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Turvallisuus"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Autotila"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 5150da9..e63b734 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Verrouillage"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nouvelle notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Clavier virtuel"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Clavier physique"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sécurité"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Mode Voiture"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3736890..019fdf2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nouvelle notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Clavier virtuel"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Clavier physique"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sécurité"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Mode Voiture"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 7575d68..219299f 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloquear"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nova"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguranza"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modo coche"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 42bad0a..90dda1a 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"લૉકડાઉન"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"નવું નોટિફિકેશન"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"વર્ચ્યુઅલ કીબોર્ડ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ભૌતિક કીબોર્ડ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"સુરક્ષા"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"કાર મોડ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 83cacea..af5bc1f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"फ़ाेन लॉक करें"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"नई सूचना"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"वर्चुअल कीबोर्ड"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"सामान्य कीबोर्ड"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"कार मोड"</string>
@@ -1136,7 +1135,7 @@
<string name="copy" msgid="5472512047143665218">"कॉपी करें"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"क्लिपबोर्ड पर कॉपी नहीं हो सका"</string>
<string name="paste" msgid="461843306215520225">"चिपकाएं"</string>
- <string name="paste_as_plain_text" msgid="7664800665823182587">"सादे पाठ के रूप में चिपकाएं"</string>
+ <string name="paste_as_plain_text" msgid="7664800665823182587">"सादे टेक्स्ट के रूप में चिपकाएं"</string>
<string name="replace" msgid="7842675434546657444">"बदलें•"</string>
<string name="delete" msgid="1514113991712129054">"मिटाएं"</string>
<string name="copyUrl" msgid="6229645005987260230">"यूआरएल को कॉपी करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6f81009..87df29a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Zaključavanje"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova obavijest"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtualna tipkovnica"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizička tipkovnica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sigurnost"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Način rada u automobilu"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 71687d4..3762fde 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Zárolás"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Új értesítés"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuális billentyűzet"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizikai billentyűzet"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Biztonság"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Autós üzemmód"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index b7146f0..a11e24b 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Արգելափակում"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Նոր ծանուցում"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Վիրտուալ ստեղնաշար"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Ֆիզիկական ստեղնաշար"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Անվտանգություն"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Մեքենայի ռեժիմ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 66fc3fb..dbccee9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Kunci total"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notifikasi baru"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Keyboard virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Keyboard fisik"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Keamanan"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Mode mobil"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 64b2340..cfefc03 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Læsing"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ný tilkynning"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Sýndarlyklaborð"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Vélbúnaðarlyklaborð"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Öryggi"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Bílastilling"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d25bb06..b05bf79 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Blocco"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nuova notifica"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Tastiera virtuale"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tastiera fisica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sicurezza"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modalità automobile"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a1373c3..8656fce 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"נעילה"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"התראה חדשה"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"מקלדת וירטואלית"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"מקלדת פיזית"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"אבטחה"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"מצב נהיגה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ed55a7f..69d0b9d 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ロックダウン"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新しい通知"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"仮想キーボード"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"物理キーボード"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"セキュリティ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"運転モード"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 0b06d7c..6d32f25 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"დაბლოკვა"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ახალი შეტყობინება"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ვირტუალური კლავიატურა"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ფიზიკური კლავიატურა"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"უსაფრთხოება"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"მანქანის რეჟიმი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index a44d09d..0d9fd3f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Құлыптау"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Жаңа хабарландыру"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуалдық пернетақта"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физикалық пернетақта"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Қауіпсіздік"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Көлік режимі"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 2fada73..0c82b66 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ការចាក់សោ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ការជូនដំណឹងថ្មី"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ក្ដារចុចនិម្មិត"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ក្ដារចុចរូបវន្ត"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"សុវត្ថិភាព"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"មុខងាររថយន្ត"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c39d9f7..e27527f 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ಲಾಕ್ಡೌನ್"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ಹೊಸ ಅಧಿಸೂಚನೆ"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ವರ್ಚುಯಲ್ ಕೀಬೋರ್ಡ್"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ಭದ್ರತೆ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"ಕಾರ್ ಮೋಡ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 55bae4d..c953a39 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -247,7 +247,7 @@
<string name="bugreport_message" msgid="5212529146119624326">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"대화형 보고서"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"대부분의 경우 이 옵션을 사용합니다. 신고 진행 상황을 추적하고 문제에 대한 세부정보를 입력하고 스크린샷을 찍을 수 있습니다. 신고하기에 시간이 너무 오래 걸리고 사용 빈도가 낮은 일부 섹션을 생략할 수 있습니다."</string>
- <string name="bugreport_option_full_title" msgid="7681035745950045690">"전체 보고서"</string>
+ <string name="bugreport_option_full_title" msgid="7681035745950045690">"전체 신고"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"기기가 응답하지 않거나 너무 느리거나 모든 보고서 섹션이 필요한 경우 이 옵션을 사용하여 시스템 방해를 최소화합니다. 세부정보를 추가하거나 스크린샷을 추가로 찍을 수 없습니다."</string>
<string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{버그 신고 스크린샷을 #초 후에 찍습니다.}other{버그 신고 스크린샷을 #초 후에 찍습니다.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"버그 신고용 스크린샷 촬영 완료"</string>
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"잠금"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"새 알림"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"가상 키보드"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"물리적 키보드"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"보안"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"운전 모드"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ad01dafc..dccc4a6 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Бекем кулпулоо"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Жаңы эскертме"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуалдык баскычтоп"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Аппараттык баскычтоп"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Коопсуздук"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Унаа режими"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 02df227..c6524de 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ລັອກໄວ້"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ການແຈ້ງເຕືອນໃໝ່"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ແປ້ນພິມສະເໝືອນ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ແປ້ນພິມພາຍນອກ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ຄວາມປອດໄພ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"ໂໝດຂັບລົດ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 4543ef6..adf30e8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Užrakinimas"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Naujas pranešimas"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtualioji klaviatūra"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizinė klaviatūra"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sauga"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Automobilio režimas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 64c855b..5631521 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloķēšana"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"Pārsniedz"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Jauns paziņojums"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuālā tastatūra"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fiziskā tastatūra"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Drošība"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Automašīnas režīms"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0af4cdd..a45d0a7 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Заклучување"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ново известување"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуелна тастатура"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физичка тастатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безбедност"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Режим на работа во автомобил"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index bc12c07..492cd54 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ലോക്ക്ഡൗൺ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"പുതിയ അറിയിപ്പ്"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"വെർച്വൽ കീബോഡ്"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ഫിസിക്കൽ കീബോഡ്"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"സുരക്ഷ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"കാർ മോഡ്"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4e8c314..2c8aaae 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Түгжих"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Шинэ мэдэгдэл"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуал гар"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Биет гар"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Аюулгүй байдал"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Машины горим"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index aa8c1e9..d47fea35 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"लॉकडाउन"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"नवीन सूचना"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"व्हर्च्युअल कीबोर्ड"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"वास्तविक कीबोर्ड"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"कार मोड"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 9a6ee3b..deb343d 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Kunci semua"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Pemberitahuan baharu"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Papan kekunci maya"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Papan kekunci fizikal"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Keselamatan"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Mod kereta"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 716f5d7..5f41672 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"လော့ခ်ဒေါင်း"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"၉၉၉+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"အကြောင်းကြားချက်အသစ်"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ပကတိအသွင်ကီးဘုတ်"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"စက်၏ ကီးဘုတ်"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"လုံခြုံရေး"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"ကားမုဒ်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3d16ea7..0c9a983 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Låsing"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nytt varsel"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuelt tastatur"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysisk tastatur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sikkerhet"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Bilmodus"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index bdb31bc..e95d48b 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"लकडाउन गर्नु…"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"९९९+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"नयाँ सूचना"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"भर्चुअल किबोर्ड"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"फिजिकल किबोर्ड"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"कार मोड"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 162d3e8..5723510 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999 +"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nieuwe melding"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtueel toetsenbord"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysiek toetsenbord"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Beveiliging"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Automodus"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 440245e..c4150dc 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ଲକ୍ କରନ୍ତୁ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ନୂଆ ବିଜ୍ଞପ୍ତି"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ଭର୍ଚୁଆଲ୍ କୀ\'ବୋର୍ଡ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ଫିଜିକଲ୍ କୀ’ବୋର୍ଡ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ସୁରକ୍ଷା"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"କାର୍ ମୋଡ୍"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index a9e3531..96917c0 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ਲਾਕਡਾਊਨ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ਨਵੀਂ ਸੂਚਨਾ"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ਆਭਾਸੀ ਕੀ-ਬੋਰਡ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ਸੁਰੱਖਿਆ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"ਕਾਰ ਮੋਡ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7b47a5c..be9d322 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Blokada"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nowe powiadomienie"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Klawiatura wirtualna"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Klawiatura fizyczna"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Bezpieczeństwo"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Tryb samochodowy"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8635d76..ff352b1 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueio total"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurança"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modo carro"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5dc59e1..d343af6 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloquear"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurança"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modo automóvel"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8635d76..ff352b1 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueio total"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurança"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modo carro"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index acd1df6..b560b07 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Blocare strictă"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"˃999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificare nouă"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Tastatură virtuală"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tastatură fizică"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Securitate"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Mod Mașină"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fb4775b..fbe67e2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Блокировка входа"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Новое уведомление"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуальная клавиатура"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физическая клавиатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безопасность"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Режим \"В авто\""</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 098e622..4cec877 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"අගුලු දැමීම"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"නව දැනුම්දීම"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"අතථ්ය යතුරු පුවරුව"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"භෞතික යතුරු පුවරුව"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ආරක්ෂාව"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"මෝටර් රථ ආකාරය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 47e3d3b..b98364a 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Uzamknúť"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nové upozornenie"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuálna klávesnica"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyzická klávesnica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Zabezpečenie"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Režim v aute"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 6e722e3..6972abb 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Zakleni"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999 +"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Novo obvestilo"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Navidezna tipkovnica"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizična tipkovnica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Varnost"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Način za avtomobil"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 0a70e9a..cbac0f0 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Blloko"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Njoftim i ri"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Tastiera virtuale"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tastiera fizike"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Siguria"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Modaliteti \"në makinë\""</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 0e50810..d5549e7 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -265,7 +265,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Закључавање"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ново обавештење"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Виртуелна тастатура"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физичка тастатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безбедност"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Режим рада у аутомобилу"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f8b3fdf..d1c579d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Låsning"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ny avisering"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuellt tangentbord"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysiskt tangentbord"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Säkerhet"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Billäge"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5829fae..2bc3f57 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Funga"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Arifa mpya"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Kibodi pepe"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Kibodi halisi"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Usalama"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Hali ya gari"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 1533c36..9e48a47 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"பூட்டு"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"புதிய அறிவிப்பு"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"விர்ச்சுவல் கீபோர்டு"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"கைமுறை கீபோர்டு"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"பாதுகாப்பு"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"கார் பயன்முறை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 313bc80..eff08bc 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"లాక్ చేయి"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"కొత్త నోటిఫికేషన్"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"వర్చువల్ కీబోర్డ్"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"భౌతిక కీబోర్డ్"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"సెక్యూరిటీ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"కార్ మోడ్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 447b42b..72cbc36 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"ปิดล็อก"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"การแจ้งเตือนใหม่"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"แป้นพิมพ์เสมือน"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"แป้นพิมพ์จริง"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ความปลอดภัย"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"โหมดรถยนต์"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 9aaa1b8..e66999d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"I-lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Bagong notification"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual na keyboard"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Pisikal na keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguridad"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Car mode"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 2f80037..b6c4b4a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Tam gizlilik"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Yeni bildirim"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Sanal klavye"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fiziksel klavye"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Güvenlik"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Araç modu"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b7bb63b..c408c51 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -266,7 +266,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Блокування"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Нове сповіщення"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Віртуальна клавіатура"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Фізична клавіатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безпека"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Режим автомобіля"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 58e342f..7784431 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"مقفل"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"نئی اطلاع"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"ورچوئل کی بورڈ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"فزیکل کی بورڈ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"سیکیورٹی"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"کار وضع"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index cf4478d..5ac689d1 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloklash"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Yangi bildirishnoma"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtual klaviatura"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tashqi klaviatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Xavfsizlik"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Avtomobil rejimi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1a1bb91..e1b479c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Khóa"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Thông báo mới"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Bàn phím ảo"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Bàn phím vật lý"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Bảo mật"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Chế độ trên ô tô"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 4cb587b..5fce25e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新通知"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"虚拟键盘"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"实体键盘"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"车载模式"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index b9185b7..61a3f20 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新通知"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"虛擬鍵盤"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"實體鍵盤"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"車用模式"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 4baced8..10dc699 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"超過 999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新通知"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"虛擬鍵盤"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"實體鍵盤"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"車用模式"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 23a557a..66d639e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -264,7 +264,6 @@
<string name="global_action_lockdown" msgid="2475471405907902963">"Khiya"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Isaziso esisha"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Ikhibhodi ebonakalayo"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Ikhibhodi ephathekayo"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Ukuphepha"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Imodi yemoto"</string>
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index fa4952e1..5553902 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -25,11 +25,12 @@
import android.test.AndroidTestCase;
import android.util.AttributeSet;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import androidx.test.filters.LargeTest;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index e750454..1c7ab74 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -23,13 +23,14 @@
import android.os.Parcel;
import android.util.Pair;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
index fd625dce..025e831 100644
--- a/core/tests/coretests/src/android/util/BinaryXmlTest.java
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -30,6 +30,9 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
index 1cd4d13..91ebc2a 100644
--- a/core/tests/coretests/src/android/util/XmlTest.java
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -29,6 +29,8 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index f5fcb03..297b07f 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -20,8 +20,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
@@ -33,6 +35,7 @@
import java.util.Locale;
import java.util.Objects;
+import java.util.function.Supplier;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -41,28 +44,28 @@
public void verifyLocale(final String localeString) {
// InputMethodSubtype#getLocale() returns exactly the same string that is passed to the
// constructor.
- assertEquals(localeString, createDummySubtype(localeString).getLocale());
+ assertEquals(localeString, createSubtype(localeString).getLocale());
// InputMethodSubtype#getLocale() should be preserved via marshaling.
- assertEquals(createDummySubtype(localeString).getLocale(),
- cloneViaParcel(createDummySubtype(localeString)).getLocale());
+ assertEquals(createSubtype(localeString).getLocale(),
+ cloneViaParcel(createSubtype(localeString)).getLocale());
// InputMethodSubtype#getLocale() should be preserved via marshaling.
- assertEquals(createDummySubtype(localeString).getLocale(),
- cloneViaParcel(cloneViaParcel(createDummySubtype(localeString))).getLocale());
+ assertEquals(createSubtype(localeString).getLocale(),
+ cloneViaParcel(cloneViaParcel(createSubtype(localeString))).getLocale());
// Make sure InputMethodSubtype#hashCode() returns the same hash code.
- assertEquals(createDummySubtype(localeString).hashCode(),
- createDummySubtype(localeString).hashCode());
- assertEquals(createDummySubtype(localeString).hashCode(),
- cloneViaParcel(createDummySubtype(localeString)).hashCode());
- assertEquals(createDummySubtype(localeString).hashCode(),
- cloneViaParcel(cloneViaParcel(createDummySubtype(localeString))).hashCode());
+ assertEquals(createSubtype(localeString).hashCode(),
+ createSubtype(localeString).hashCode());
+ assertEquals(createSubtype(localeString).hashCode(),
+ cloneViaParcel(createSubtype(localeString)).hashCode());
+ assertEquals(createSubtype(localeString).hashCode(),
+ cloneViaParcel(cloneViaParcel(createSubtype(localeString))).hashCode());
}
@Test
public void testLocaleObj_locale() {
- final InputMethodSubtype usSubtype = createDummySubtype("en_US");
+ final InputMethodSubtype usSubtype = createSubtype("en_US");
Locale localeObject = usSubtype.getLocaleObject();
assertEquals("en", localeObject.getLanguage());
assertEquals("US", localeObject.getCountry());
@@ -73,7 +76,7 @@
@Test
public void testLocaleObj_languageTag() {
- final InputMethodSubtype usSubtype = createDummySubtypeUsingLanguageTag("en-US");
+ final InputMethodSubtype usSubtype = createSubtypeUsingLanguageTag("en-US");
Locale localeObject = usSubtype.getLocaleObject();
assertNotNull(localeObject);
assertEquals("en", localeObject.getLanguage());
@@ -85,7 +88,7 @@
@Test
public void testLocaleObj_emptyLocale() {
- final InputMethodSubtype emptyLocaleSubtype = createDummySubtype("");
+ final InputMethodSubtype emptyLocaleSubtype = createSubtype("");
assertNull(emptyLocaleSubtype.getLocaleObject());
// It should continue returning null when called multiple times.
assertNull(emptyLocaleSubtype.getLocaleObject());
@@ -110,8 +113,8 @@
@Test
public void testDeprecatedLocaleString() throws Exception {
// Make sure "iw" is not automatically replaced with "he".
- final InputMethodSubtype subtypeIw = createDummySubtype("iw");
- final InputMethodSubtype subtypeHe = createDummySubtype("he");
+ final InputMethodSubtype subtypeIw = createSubtype("iw");
+ final InputMethodSubtype subtypeHe = createSubtype("he");
assertEquals("iw", subtypeIw.getLocale());
assertEquals("he", subtypeHe.getLocale());
assertFalse(Objects.equals(subtypeIw, subtypeHe));
@@ -125,6 +128,64 @@
assertEquals("he", clonedSubtypeHe.getLocale());
}
+ @Test
+ public void testCanonicalizedLanguageTagObjectCache() {
+ final InputMethodSubtype subtype = createSubtypeUsingLanguageTag("en-US");
+ // Verify that the returned object is cached and any subsequent call should return the same
+ // object, which is strictly guaranteed if the method gets called only on a single thread.
+ assertSame(subtype.getCanonicalizedLanguageTag(), subtype.getCanonicalizedLanguageTag());
+ }
+
+ @Test
+ public void testCanonicalizedLanguageTag() {
+ verifyCanonicalizedLanguageTag("en", "en");
+ verifyCanonicalizedLanguageTag("en-US", "en-US");
+ verifyCanonicalizedLanguageTag("en-Latn-US-t-k0-qwerty", "en-Latn-US-t-k0-qwerty");
+
+ verifyCanonicalizedLanguageTag("en-us", "en-US");
+ verifyCanonicalizedLanguageTag("EN-us", "en-US");
+
+ verifyCanonicalizedLanguageTag(null, "");
+ verifyCanonicalizedLanguageTag("", "");
+
+ verifyCanonicalizedLanguageTag("und", "und");
+ verifyCanonicalizedLanguageTag("apparently invalid language tag!!!", "und");
+ }
+
+ private void verifyCanonicalizedLanguageTag(
+ @Nullable String languageTag, @Nullable String expectedLanguageTag) {
+ final InputMethodSubtype subtype = createSubtypeUsingLanguageTag(languageTag);
+ assertEquals(subtype.getCanonicalizedLanguageTag(), expectedLanguageTag);
+ }
+
+ @Test
+ public void testIsSuitableForPhysicalKeyboardLayoutMapping() {
+ final Supplier<InputMethodSubtypeBuilder> getValidBuilder = () ->
+ new InputMethodSubtypeBuilder()
+ .setLanguageTag("en-US")
+ .setIsAuxiliary(false)
+ .setSubtypeMode("keyboard")
+ .setSubtypeId(1);
+
+ assertTrue(getValidBuilder.get().build().isSuitableForPhysicalKeyboardLayoutMapping());
+
+ // mode == "voice" is not suitable.
+ assertFalse(getValidBuilder.get().setSubtypeMode("voice").build()
+ .isSuitableForPhysicalKeyboardLayoutMapping());
+
+ // Auxiliary subtype not suitable.
+ assertFalse(getValidBuilder.get().setIsAuxiliary(true).build()
+ .isSuitableForPhysicalKeyboardLayoutMapping());
+
+ // languageTag == null is not suitable.
+ assertFalse(getValidBuilder.get().setLanguageTag(null).build()
+ .isSuitableForPhysicalKeyboardLayoutMapping());
+
+ // languageTag == "und" is not suitable.
+ assertFalse(getValidBuilder.get().setLanguageTag("und").build()
+ .isSuitableForPhysicalKeyboardLayoutMapping());
+ }
+
private static InputMethodSubtype cloneViaParcel(final InputMethodSubtype original) {
Parcel parcel = null;
try {
@@ -139,7 +200,7 @@
}
}
- private static InputMethodSubtype createDummySubtype(final String locale) {
+ private static InputMethodSubtype createSubtype(final String locale) {
final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
return builder.setSubtypeNameResId(0)
.setSubtypeIconResId(0)
@@ -148,7 +209,7 @@
.build();
}
- private static InputMethodSubtype createDummySubtypeUsingLanguageTag(
+ private static InputMethodSubtype createSubtypeUsingLanguageTag(
final String languageTag) {
final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
return builder.setSubtypeNameResId(0)
diff --git a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
index 04dfd6e..de325ab 100644
--- a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
@@ -23,6 +23,9 @@
import android.annotation.NonNull;
import android.util.ExceptionUtils;
+import com.android.modules.utils.FastDataInput;
+import com.android.modules.utils.FastDataOutput;
+
import libcore.util.HexEncoding;
import org.junit.Assume;
@@ -39,6 +42,8 @@
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
@@ -61,14 +66,32 @@
this.use4ByteSequence = use4ByteSequence;
}
+ @NonNull
+ private FastDataInput createFastDataInput(@NonNull InputStream in, int bufferSize) {
+ if (use4ByteSequence) {
+ return new ArtFastDataInput(in, bufferSize);
+ } else {
+ return new FastDataInput(in, bufferSize);
+ }
+ }
+
+ @NonNull
+ private FastDataOutput createFastDataOutput(@NonNull OutputStream out, int bufferSize) {
+ if (use4ByteSequence) {
+ return new ArtFastDataOutput(out, bufferSize);
+ } else {
+ return new FastDataOutput(out, bufferSize);
+ }
+ }
+
@Test
public void testEndOfFile_Int() throws Exception {
- try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
- new byte[] { 1 }), 1000, use4ByteSequence)) {
+ try (FastDataInput in = createFastDataInput(new ByteArrayInputStream(
+ new byte[] { 1 }), 1000)) {
assertThrows(EOFException.class, () -> in.readInt());
}
- try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
- new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) {
+ try (FastDataInput in = createFastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
assertEquals(1, in.readByte());
assertThrows(EOFException.class, () -> in.readInt());
}
@@ -76,25 +99,25 @@
@Test
public void testEndOfFile_String() throws Exception {
- try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
- new byte[] { 1 }), 1000, use4ByteSequence)) {
+ try (FastDataInput in = createFastDataInput(new ByteArrayInputStream(
+ new byte[] { 1 }), 1000)) {
assertThrows(EOFException.class, () -> in.readUTF());
}
- try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
- new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) {
+ try (FastDataInput in = createFastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
assertThrows(EOFException.class, () -> in.readUTF());
}
}
@Test
public void testEndOfFile_Bytes_Small() throws Exception {
- try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
- new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) {
+ try (FastDataInput in = createFastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
final byte[] tmp = new byte[10];
assertThrows(EOFException.class, () -> in.readFully(tmp));
}
- try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
- new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) {
+ try (FastDataInput in = createFastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
final byte[] tmp = new byte[10_000];
assertThrows(EOFException.class, () -> in.readFully(tmp));
}
@@ -103,8 +126,7 @@
@Test
public void testUTF_Bounds() throws Exception {
final char[] buf = new char[65_534];
- try (FastDataOutput out = new FastDataOutput(new ByteArrayOutputStream(),
- BOUNCE_SIZE, use4ByteSequence)) {
+ try (FastDataOutput out = createFastDataOutput(new ByteArrayOutputStream(), BOUNCE_SIZE)) {
// Writing simple string will fit fine
Arrays.fill(buf, '!');
final String simple = new String(buf);
@@ -132,17 +154,15 @@
doTranscodeWrite(out);
out.flush();
- final FastDataInput in = new FastDataInput(
- new ByteArrayInputStream(outStream.toByteArray()),
- BOUNCE_SIZE, use4ByteSequence);
+ final FastDataInput in = createFastDataInput(
+ new ByteArrayInputStream(outStream.toByteArray()), BOUNCE_SIZE);
doTranscodeRead(in);
}
// Verify that fast data can be read by upstream
{
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- final FastDataOutput out = new FastDataOutput(outStream,
- BOUNCE_SIZE, use4ByteSequence);
+ final FastDataOutput out = createFastDataOutput(outStream, BOUNCE_SIZE);
doTranscodeWrite(out);
out.flush();
@@ -299,7 +319,7 @@
final DataOutput slowData = new DataOutputStream(slowStream);
final ByteArrayOutputStream fastStream = new ByteArrayOutputStream();
- final FastDataOutput fastData = FastDataOutput.obtainUsing3ByteSequences(fastStream);
+ final FastDataOutput fastData = FastDataOutput.obtain(fastStream);
for (int cp = Character.MIN_CODE_POINT; cp < Character.MAX_CODE_POINT; cp++) {
if (Character.isValidCodePoint(cp)) {
@@ -416,16 +436,14 @@
private void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out,
@NonNull ThrowingConsumer<FastDataInput> in, int count) throws Exception {
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- final FastDataOutput outData = new FastDataOutput(outStream,
- BOUNCE_SIZE, use4ByteSequence);
+ final FastDataOutput outData = createFastDataOutput(outStream, BOUNCE_SIZE);
for (int i = 0; i < count; i++) {
out.accept(outData);
}
outData.flush();
final ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
- final FastDataInput inData = new FastDataInput(inStream,
- BOUNCE_SIZE, use4ByteSequence);
+ final FastDataInput inData = createFastDataInput(inStream, BOUNCE_SIZE);
for (int i = 0; i < count; i++) {
in.accept(inData);
}
diff --git a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
index 06e9759..0484068 100644
--- a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
@@ -18,10 +18,11 @@
import static org.junit.Assert.assertArrayEquals;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
diff --git a/errorprone/refaster/EfficientXml.java b/errorprone/refaster/EfficientXml.java
index ae797c4..87a902a 100644
--- a/errorprone/refaster/EfficientXml.java
+++ b/errorprone/refaster/EfficientXml.java
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
diff --git a/errorprone/refaster/EfficientXml.java.refaster b/errorprone/refaster/EfficientXml.java.refaster
index 750c2db..c285e9b 100644
--- a/errorprone/refaster/EfficientXml.java.refaster
+++ b/errorprone/refaster/EfficientXml.java.refaster
Binary files differ
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 00be5a6e..77284c41 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -109,6 +109,12 @@
return (mSplitRule instanceof SplitPlaceholderRule);
}
+ @NonNull
+ SplitInfo toSplitInfo() {
+ return new SplitInfo(mPrimaryContainer.toActivityStack(),
+ mSecondaryContainer.toActivityStack(), mSplitAttributes);
+ }
+
static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
final boolean shouldFinishPrimaryWithSecondary = (splitRule instanceof SplitPairRule)
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 bf7326a..1d513e4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -1422,6 +1422,11 @@
@GuardedBy("mLock")
void updateContainer(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container) {
+ if (!container.getTaskContainer().isVisible()) {
+ // Wait until the Task is visible to avoid unnecessary update when the Task is still in
+ // background.
+ return;
+ }
if (launchPlaceholderIfNecessary(wct, container)) {
// Placeholder was launched, the positions will be updated when the activity is added
// to the secondary container.
@@ -1643,16 +1648,14 @@
/**
* Notifies listeners about changes to split states if necessary.
*/
+ @VisibleForTesting
@GuardedBy("mLock")
- private void updateCallbackIfNecessary() {
- if (mEmbeddingCallback == null) {
+ void updateCallbackIfNecessary() {
+ if (mEmbeddingCallback == null || !readyToReportToClient()) {
return;
}
- if (!allActivitiesCreated()) {
- return;
- }
- List<SplitInfo> currentSplitStates = getActiveSplitStates();
- if (currentSplitStates == null || mLastReportedSplitStates.equals(currentSplitStates)) {
+ final List<SplitInfo> currentSplitStates = getActiveSplitStates();
+ if (mLastReportedSplitStates.equals(currentSplitStates)) {
return;
}
mLastReportedSplitStates.clear();
@@ -1661,48 +1664,27 @@
}
/**
- * @return a list of descriptors for currently active split states. If the value returned is
- * null, that indicates that the active split states are in an intermediate state and should
- * not be reported.
+ * Returns a list of descriptors for currently active split states.
*/
@GuardedBy("mLock")
- @Nullable
+ @NonNull
private List<SplitInfo> getActiveSplitStates() {
- List<SplitInfo> splitStates = new ArrayList<>();
+ final List<SplitInfo> splitStates = new ArrayList<>();
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<SplitContainer> splitContainers = mTaskContainers.valueAt(i)
- .mSplitContainers;
- for (SplitContainer container : splitContainers) {
- if (container.getPrimaryContainer().isEmpty()
- || container.getSecondaryContainer().isEmpty()) {
- // We are in an intermediate state because either the split container is about
- // to be removed or the primary or secondary container are about to receive an
- // activity.
- return null;
- }
- final ActivityStack primaryContainer = container.getPrimaryContainer()
- .toActivityStack();
- final ActivityStack secondaryContainer = container.getSecondaryContainer()
- .toActivityStack();
- final SplitInfo splitState = new SplitInfo(primaryContainer, secondaryContainer,
- container.getSplitAttributes());
- splitStates.add(splitState);
- }
+ mTaskContainers.valueAt(i).getSplitStates(splitStates);
}
return splitStates;
}
/**
- * Checks if all activities that are registered with the containers have already appeared in
- * the client.
+ * Whether we can now report the split states to the client.
*/
- private boolean allActivitiesCreated() {
+ @GuardedBy("mLock")
+ private boolean readyToReportToClient() {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
- for (TaskFragmentContainer container : containers) {
- if (!container.taskInfoActivityCountMatchesCreated()) {
- return false;
- }
+ if (mTaskContainers.valueAt(i).isInIntermediateState()) {
+ // If any Task is in an intermediate state, wait for the server update.
+ return false;
}
}
return true;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 00943f2d..231da05 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -221,6 +221,24 @@
return mContainers.indexOf(child);
}
+ /** Whether the Task is in an intermediate state waiting for the server update.*/
+ boolean isInIntermediateState() {
+ for (TaskFragmentContainer container : mContainers) {
+ if (container.isInIntermediateState()) {
+ // We are in an intermediate state to wait for server update on this TaskFragment.
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Adds the descriptors of split states in this Task to {@code outSplitStates}. */
+ void getSplitStates(@NonNull List<SplitInfo> outSplitStates) {
+ for (SplitContainer container : mSplitContainers) {
+ outSplitStates.add(container.toSplitInfo());
+ }
+ }
+
/**
* A wrapper class which contains the display ID and {@link Configuration} of a
* {@link TaskContainer}
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 18712ae..71b8840 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -166,16 +166,34 @@
return allActivities;
}
- /**
- * Checks if the count of activities from the same process in task fragment info corresponds to
- * the ones created and available on the client side.
- */
- boolean taskInfoActivityCountMatchesCreated() {
+ /** Whether the TaskFragment is in an intermediate state waiting for the server update.*/
+ boolean isInIntermediateState() {
if (mInfo == null) {
- return false;
+ // Haven't received onTaskFragmentAppeared event.
+ return true;
}
- return mPendingAppearedActivities.isEmpty()
- && mInfo.getActivities().size() == collectNonFinishingActivities().size();
+ if (mInfo.isEmpty()) {
+ // Empty TaskFragment will be removed or will have activity launched into it soon.
+ return true;
+ }
+ if (!mPendingAppearedActivities.isEmpty()) {
+ // Reparented activity hasn't appeared.
+ return true;
+ }
+ // Check if there is any reported activity that is no longer alive.
+ for (IBinder token : mInfo.getActivities()) {
+ final Activity activity = mController.getActivity(token);
+ if (activity == null && !mTaskContainer.isVisible()) {
+ // Activity can be null if the activity is not attached to process yet. That can
+ // happen when the activity is started in background.
+ continue;
+ }
+ if (activity == null || activity.isFinishing()) {
+ // One of the reported activity is no longer alive, wait for the server update.
+ return true;
+ }
+ }
+ return false;
}
@NonNull
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 a403031..87d0278 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
@@ -102,6 +102,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
/**
* Test class for {@link SplitController}.
@@ -132,6 +133,8 @@
private SplitController mSplitController;
private SplitPresenter mSplitPresenter;
+ private Consumer<List<SplitInfo>> mEmbeddingCallback;
+ private List<SplitInfo> mSplitInfos;
private TransactionManager mTransactionManager;
@Before
@@ -141,9 +144,16 @@
.getCurrentWindowLayoutInfo(anyInt(), any());
mSplitController = new SplitController(mWindowLayoutComponent);
mSplitPresenter = mSplitController.mPresenter;
+ mSplitInfos = new ArrayList<>();
+ mEmbeddingCallback = splitInfos -> {
+ mSplitInfos.clear();
+ mSplitInfos.addAll(splitInfos);
+ };
+ mSplitController.setSplitInfoCallback(mEmbeddingCallback);
mTransactionManager = mSplitController.mTransactionManager;
spyOn(mSplitController);
spyOn(mSplitPresenter);
+ spyOn(mEmbeddingCallback);
spyOn(mTransactionManager);
doNothing().when(mSplitPresenter).applyTransaction(any(), anyInt(), anyBoolean());
final Configuration activityConfig = new Configuration();
@@ -329,6 +339,30 @@
}
@Test
+ public void testUpdateContainer_skipIfTaskIsInvisible() {
+ final Activity r0 = createMockActivity();
+ final Activity r1 = createMockActivity();
+ addSplitTaskFragments(r0, r1);
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ final TaskFragmentContainer taskFragmentContainer = taskContainer.mContainers.get(0);
+ spyOn(taskContainer);
+
+ // No update when the Task is invisible.
+ clearInvocations(mSplitPresenter);
+ doReturn(false).when(taskContainer).isVisible();
+ mSplitController.updateContainer(mTransaction, taskFragmentContainer);
+
+ verify(mSplitPresenter, never()).updateSplitContainer(any(), any(), any());
+
+ // Update the split when the Task is visible.
+ doReturn(true).when(taskContainer).isVisible();
+ mSplitController.updateContainer(mTransaction, taskFragmentContainer);
+
+ verify(mSplitPresenter).updateSplitContainer(taskContainer.mSplitContainers.get(0),
+ taskFragmentContainer, mTransaction);
+ }
+
+ @Test
public void testOnStartActivityResultError() {
final Intent intent = new Intent();
final TaskContainer taskContainer = createTestTaskContainer();
@@ -1162,14 +1196,69 @@
new WindowMetrics(TASK_BOUNDS, WindowInsets.CONSUMED)));
}
+ @Test
+ public void testSplitInfoCallback_reportSplit() {
+ final Activity r0 = createMockActivity();
+ final Activity r1 = createMockActivity();
+ addSplitTaskFragments(r0, r1);
+
+ mSplitController.updateCallbackIfNecessary();
+ assertEquals(1, mSplitInfos.size());
+ final SplitInfo splitInfo = mSplitInfos.get(0);
+ assertEquals(1, splitInfo.getPrimaryActivityStack().getActivities().size());
+ assertEquals(1, splitInfo.getSecondaryActivityStack().getActivities().size());
+ assertEquals(r0, splitInfo.getPrimaryActivityStack().getActivities().get(0));
+ assertEquals(r1, splitInfo.getSecondaryActivityStack().getActivities().get(0));
+ }
+
+ @Test
+ public void testSplitInfoCallback_reportSplitInMultipleTasks() {
+ final int taskId0 = 1;
+ final int taskId1 = 2;
+ final Activity r0 = createMockActivity(taskId0);
+ final Activity r1 = createMockActivity(taskId0);
+ final Activity r2 = createMockActivity(taskId1);
+ final Activity r3 = createMockActivity(taskId1);
+ addSplitTaskFragments(r0, r1);
+ addSplitTaskFragments(r2, r3);
+
+ mSplitController.updateCallbackIfNecessary();
+ assertEquals(2, mSplitInfos.size());
+ }
+
+ @Test
+ public void testSplitInfoCallback_doNotReportIfInIntermediateState() {
+ final Activity r0 = createMockActivity();
+ final Activity r1 = createMockActivity();
+ addSplitTaskFragments(r0, r1);
+ final TaskFragmentContainer tf0 = mSplitController.getContainerWithActivity(r0);
+ final TaskFragmentContainer tf1 = mSplitController.getContainerWithActivity(r1);
+ spyOn(tf0);
+ spyOn(tf1);
+
+ // Do not report if activity has not appeared in the TaskFragmentContainer in split.
+ doReturn(true).when(tf0).isInIntermediateState();
+ mSplitController.updateCallbackIfNecessary();
+ verify(mEmbeddingCallback, never()).accept(any());
+
+ doReturn(false).when(tf0).isInIntermediateState();
+ mSplitController.updateCallbackIfNecessary();
+ verify(mEmbeddingCallback).accept(any());
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
+ return createMockActivity(TASK_ID);
+ }
+
+ /** Creates a mock activity in the organizer process. */
+ private Activity createMockActivity(int taskId) {
final Activity activity = mock(Activity.class);
doReturn(mActivityResources).when(activity).getResources();
final IBinder activityToken = new Binder();
doReturn(activityToken).when(activity).getActivityToken();
doReturn(activity).when(mSplitController).getActivity(activityToken);
- doReturn(TASK_ID).when(activity).getTaskId();
+ doReturn(taskId).when(activity).getTaskId();
doReturn(new ActivityInfo()).when(activity).getActivityInfo();
doReturn(DEFAULT_DISPLAY).when(activity).getDisplayId();
return activity;
@@ -1177,7 +1266,8 @@
/** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) {
- final TaskFragmentContainer container = mSplitController.newContainer(activity, TASK_ID);
+ final TaskFragmentContainer container = mSplitController.newContainer(activity,
+ activity.getTaskId());
setupTaskFragmentInfo(container, activity);
return container;
}
@@ -1268,7 +1358,7 @@
// We need to set those in case we are not respecting clear top.
// TODO(b/231845476) we should always respect clearTop.
- final int windowingMode = mSplitController.getTaskContainer(TASK_ID)
+ final int windowingMode = mSplitController.getTaskContainer(primaryContainer.getTaskId())
.getWindowingModeForSplitTaskFragment(TASK_BOUNDS);
primaryContainer.setLastRequestedWindowingMode(windowingMode);
secondaryContainer.setLastRequestedWindowingMode(windowingMode);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 35415d8..d43c471 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -334,6 +334,70 @@
assertFalse(container.hasActivity(mActivity.getActivityToken()));
}
+ @Test
+ public void testIsInIntermediateState() {
+ // True if no info set.
+ final TaskContainer taskContainer = createTestTaskContainer();
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ mIntent, taskContainer, mController);
+ spyOn(taskContainer);
+ doReturn(true).when(taskContainer).isVisible();
+
+ assertTrue(container.isInIntermediateState());
+ assertTrue(taskContainer.isInIntermediateState());
+
+ // True if empty info set.
+ final List<IBinder> activities = new ArrayList<>();
+ doReturn(activities).when(mInfo).getActivities();
+ doReturn(true).when(mInfo).isEmpty();
+ container.setInfo(mTransaction, mInfo);
+
+ assertTrue(container.isInIntermediateState());
+ assertTrue(taskContainer.isInIntermediateState());
+
+ // False if info is not empty.
+ doReturn(false).when(mInfo).isEmpty();
+ container.setInfo(mTransaction, mInfo);
+
+ assertFalse(container.isInIntermediateState());
+ assertFalse(taskContainer.isInIntermediateState());
+
+ // True if there is pending appeared activity.
+ container.addPendingAppearedActivity(mActivity);
+
+ assertTrue(container.isInIntermediateState());
+ assertTrue(taskContainer.isInIntermediateState());
+
+ // True if the activity is finishing.
+ activities.add(mActivity.getActivityToken());
+ doReturn(true).when(mActivity).isFinishing();
+ container.setInfo(mTransaction, mInfo);
+
+ assertTrue(container.isInIntermediateState());
+ assertTrue(taskContainer.isInIntermediateState());
+
+ // False if the activity is not finishing.
+ doReturn(false).when(mActivity).isFinishing();
+ container.setInfo(mTransaction, mInfo);
+
+ assertFalse(container.isInIntermediateState());
+ assertFalse(taskContainer.isInIntermediateState());
+
+ // True if there is a token that can't find associated activity.
+ activities.clear();
+ activities.add(new Binder());
+ container.setInfo(mTransaction, mInfo);
+
+ assertTrue(container.isInIntermediateState());
+ assertTrue(taskContainer.isInIntermediateState());
+
+ // False if there is a token that can't find associated activity when the Task is invisible.
+ doReturn(false).when(taskContainer).isVisible();
+
+ assertFalse(container.isInIntermediateState());
+ assertFalse(taskContainer.isInIntermediateState());
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
final Activity activity = mock(Activity.class);
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 db5de43..dc5b9a1e 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
@@ -72,13 +72,9 @@
private static final String TAG = "BackAnimationController";
private static final int SETTING_VALUE_OFF = 0;
private static final int SETTING_VALUE_ON = 1;
- private static final String PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP =
- "persist.wm.debug.predictive_back_progress_threshold";
public static final boolean IS_ENABLED =
SystemProperties.getInt("persist.wm.debug.predictive_back",
- SETTING_VALUE_ON) != SETTING_VALUE_ON;
- private static final int PROGRESS_THRESHOLD = SystemProperties
- .getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
+ SETTING_VALUE_ON) == SETTING_VALUE_ON;
/** Flag for U animation features */
public static boolean IS_U_ANIMATION_ENABLED =
SystemProperties.getInt("persist.wm.debug.predictive_back_anim",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 266cf29..66202ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -21,12 +21,10 @@
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.content.ComponentName;
-import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IDisplayWindowInsetsController;
@@ -43,7 +41,7 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.view.IInputMethodManager;
+import com.android.internal.inputmethod.IInputMethodManagerGlobal;
import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
@@ -514,16 +512,10 @@
}
void removeImeSurface() {
- final IInputMethodManager imms = getImms();
- if (imms != null) {
- try {
- // Remove the IME surface to make the insets invisible for
- // non-client controlled insets.
- imms.removeImeSurface();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to remove IME surface.", e);
- }
- }
+ // Remove the IME surface to make the insets invisible for
+ // non-client controlled insets.
+ IInputMethodManagerGlobal.removeImeSurface(
+ e -> Slog.e(TAG, "Failed to remove IME surface.", e));
}
/**
@@ -597,11 +589,6 @@
}
}
- public IInputMethodManager getImms() {
- return IInputMethodManager.Stub.asInterface(
- ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
- }
-
private static boolean haveSameLeash(InsetsSourceControl a, InsetsSourceControl b) {
if (a == b) {
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 9c2c2fa..af79386 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -619,12 +619,13 @@
// Animation length is already expected to be scaled.
va.overrideDurationScale(1.0f);
va.setDuration(anim.computeDurationHint());
- va.addUpdateListener(animation -> {
+ final ValueAnimator.AnimatorUpdateListener updateListener = animation -> {
final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
position, cornerRadius, clipRect);
- });
+ };
+ va.addUpdateListener(updateListener);
final Runnable finisher = () -> {
applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
@@ -637,20 +638,30 @@
});
};
va.addListener(new AnimatorListenerAdapter() {
+ // It is possible for the end/cancel to be called more than once, which may cause
+ // issues if the animating surface has already been released. Track the finished
+ // state here to skip duplicate callbacks. See b/252872225.
private boolean mFinished = false;
@Override
public void onAnimationEnd(Animator animation) {
- if (mFinished) return;
- mFinished = true;
- finisher.run();
+ onFinish();
}
@Override
public void onAnimationCancel(Animator animation) {
+ onFinish();
+ }
+
+ private void onFinish() {
if (mFinished) return;
mFinished = true;
finisher.run();
+ // The update listener can continue to be called after the animation has ended if
+ // end() is called manually again before the finisher removes the animation.
+ // Remove it manually here to prevent animating a released surface.
+ // See b/252872225.
+ va.removeUpdateListener(updateListener);
}
});
animations.add(va);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 9967e5f..a6f19e7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -39,7 +39,6 @@
import androidx.test.filters.SmallTest;
-import com.android.internal.view.IInputMethodManager;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.sysui.ShellInit;
@@ -56,8 +55,6 @@
@Mock
private SurfaceControl.Transaction mT;
@Mock
- private IInputMethodManager mMock;
- @Mock
private ShellInit mShellInit;
private DisplayImeController.PerDisplay mPerDisplay;
private Executor mExecutor;
@@ -77,10 +74,6 @@
}
}, mExecutor) {
@Override
- public IInputMethodManager getImms() {
- return mMock;
- }
- @Override
void removeImeSurface() { }
}.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0);
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 46fbe7c..5e8a623 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1020,40 +1020,6 @@
return base::unexpected(std::nullopt);
}
-template <typename TChar, typename SP>
-base::expected<size_t, NullOrIOError> ResStringPool::stringIndex(
- SP sp, std::unordered_map<SP, size_t>& map) const
-{
- AutoMutex lock(mStringIndexLock);
-
- if (map.empty()) {
- // build string index on the first call
- for (size_t i = 0; i < mHeader->stringCount; i++) {
- base::expected<SP, NullOrIOError> s;
- if constexpr(std::is_same_v<TChar, char16_t>) {
- s = stringAt(i);
- } else {
- s = string8At(i);
- }
- if (s.has_value()) {
- const auto r = map.insert({*s, i});
- if (!r.second) {
- ALOGE("failed to build string index, string id=%zu\n", i);
- }
- } else {
- return base::unexpected(s.error());
- }
- }
- }
-
- if (!map.empty()) {
- const auto result = map.find(sp);
- if (result != map.end())
- return result->second;
- }
- return base::unexpected(std::nullopt);
-}
-
base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str,
size_t strLen) const
{
@@ -1061,28 +1027,134 @@
return base::unexpected(std::nullopt);
}
- if (kDebugStringPoolNoisy) {
- ALOGI("indexOfString (%s): %s", isUTF8() ? "UTF-8" : "UTF-16",
- String8(str, strLen).string());
- }
-
- base::expected<size_t, NullOrIOError> idx;
- if (isUTF8()) {
- auto str8 = String8(str, strLen);
- idx = stringIndex<char>(StringPiece(str8.c_str(), str8.size()), mStringIndex8);
- } else {
- idx = stringIndex<char16_t>(StringPiece16(str, strLen), mStringIndex16);
- }
-
- if (UNLIKELY(!idx.has_value())) {
- return base::unexpected(idx.error());
- }
-
- if (*idx < mHeader->stringCount) {
+ if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
if (kDebugStringPoolNoisy) {
- ALOGI("MATCH! (idx=%zu)", *idx);
+ ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
}
- return *idx;
+
+ // The string pool contains UTF 8 strings; we don't want to cause
+ // temporary UTF-16 strings to be created as we search.
+ if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+ // Do a binary search for the string... this is a little tricky,
+ // because the strings are sorted with strzcmp16(). So to match
+ // the ordering, we need to convert strings in the pool to UTF-16.
+ // But we don't want to hit the cache, so instead we will have a
+ // local temporary allocation for the conversions.
+ size_t convBufferLen = strLen + 4;
+ std::vector<char16_t> convBuffer(convBufferLen);
+ ssize_t l = 0;
+ ssize_t h = mHeader->stringCount-1;
+
+ ssize_t mid;
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ int c = -1;
+ const base::expected<StringPiece, NullOrIOError> s = string8At(mid);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ if (s.has_value()) {
+ char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
+ s->size(), convBuffer.data(), convBufferLen);
+ c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen);
+ }
+ if (kDebugStringPoolNoisy) {
+ ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+ s->data(), c, (int)l, (int)mid, (int)h);
+ }
+ if (c == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("MATCH!");
+ }
+ return mid;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ } else {
+ // It is unusual to get the ID from an unsorted string block...
+ // most often this happens because we want to get IDs for style
+ // span tags; since those always appear at the end of the string
+ // block, start searching at the back.
+ String8 str8(str, strLen);
+ const size_t str8Len = str8.size();
+ for (int i=mHeader->stringCount-1; i>=0; i--) {
+ const base::expected<StringPiece, NullOrIOError> s = string8At(i);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ if (s.has_value()) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("Looking at %s, i=%d\n", s->data(), i);
+ }
+ if (str8Len == s->size()
+ && memcmp(s->data(), str8.string(), str8Len) == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("MATCH!");
+ }
+ return i;
+ }
+ }
+ }
+ }
+
+ } else {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string());
+ }
+
+ if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+ // Do a binary search for the string...
+ ssize_t l = 0;
+ ssize_t h = mHeader->stringCount-1;
+
+ ssize_t mid;
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1;
+ if (kDebugStringPoolNoisy) {
+ ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+ String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h);
+ }
+ if (c == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("MATCH!");
+ }
+ return mid;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ } else {
+ // It is unusual to get the ID from an unsorted string block...
+ // most often this happens because we want to get IDs for style
+ // span tags; since those always appear at the end of the string
+ // block, start searching at the back.
+ for (int i=mHeader->stringCount-1; i>=0; i--) {
+ const base::expected<StringPiece16, NullOrIOError> s = stringAt(i);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ if (kDebugStringPoolNoisy) {
+ ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i);
+ }
+ if (s.has_value() && strLen == s->size() &&
+ strzcmp16(s->data(), s->size(), str, strLen) == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("MATCH!");
+ }
+ return i;
+ }
+ }
+ }
}
return base::unexpected(std::nullopt);
}
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 24628cd..9309091 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -41,7 +41,6 @@
#include <array>
#include <map>
#include <memory>
-#include <unordered_map>
namespace android {
@@ -563,17 +562,8 @@
incfs::map_ptr<uint32_t> mStyles;
uint32_t mStylePoolSize; // number of uint32_t
- // mStringIndex is used to quickly map a string to its ID
- mutable Mutex mStringIndexLock;
- mutable std::unordered_map<StringPiece, size_t> mStringIndex8;
- mutable std::unordered_map<StringPiece16, size_t> mStringIndex16;
-
base::expected<StringPiece, NullOrIOError> stringDecodeAt(
size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const;
-
- template <typename TChar, typename SP=BasicStringPiece<TChar>>
- base::expected<size_t, NullOrIOError> stringIndex(
- SP str, std::unordered_map<SP, size_t>& map) const;
};
/**
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index d0d24a8..673041a 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -15,19 +15,20 @@
*/
#include "CanvasTransform.h"
-#include "Properties.h"
-#include "utils/Color.h"
+#include <SkAndroidFrameworkUtils.h>
#include <SkColorFilter.h>
#include <SkGradientShader.h>
+#include <SkHighContrastFilter.h>
#include <SkPaint.h>
#include <SkShader.h>
+#include <log/log.h>
#include <algorithm>
#include <cmath>
-#include <log/log.h>
-#include <SkHighContrastFilter.h>
+#include "Properties.h"
+#include "utils/Color.h"
namespace android::uirenderer {
@@ -82,27 +83,21 @@
paint.setColor(newColor);
if (paint.getShader()) {
- SkShader::GradientInfo info;
+ SkAndroidFrameworkUtils::LinearGradientInfo info;
std::array<SkColor, 10> _colorStorage;
std::array<SkScalar, _colorStorage.size()> _offsetStorage;
info.fColorCount = _colorStorage.size();
info.fColors = _colorStorage.data();
info.fColorOffsets = _offsetStorage.data();
- SkShader::GradientType type = paint.getShader()->asAGradient(&info);
- if (info.fColorCount <= 10) {
- switch (type) {
- case SkShader::kLinear_GradientType:
- for (int i = 0; i < info.fColorCount; i++) {
- info.fColors[i] = transformColor(transform, info.fColors[i]);
- }
- paint.setShader(SkGradientShader::MakeLinear(info.fPoint, info.fColors,
- info.fColorOffsets, info.fColorCount,
- info.fTileMode, info.fGradientFlags, nullptr));
- break;
- default:break;
+ if (SkAndroidFrameworkUtils::ShaderAsALinearGradient(paint.getShader(), &info) &&
+ info.fColorCount <= _colorStorage.size()) {
+ for (int i = 0; i < info.fColorCount; i++) {
+ info.fColors[i] = transformColor(transform, info.fColors[i]);
}
-
+ paint.setShader(SkGradientShader::MakeLinear(
+ info.fPoints, info.fColors, info.fColorOffsets, info.fColorCount,
+ info.fTileMode, info.fGradientFlags, nullptr));
}
}
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 92ce772..7f843a2 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -10,10 +10,15 @@
<string name="passkey_creation_intro_body">Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more</string>
<string name="choose_provider_title">Choose your default provider</string>
<string name="choose_provider_body">This provider will store passkeys and passwords for you and help you easily autofill and sign in. Learn more</string>
- <string name="choose_create_option_title">Create a passkey at</string>
+ <string name="choose_create_option_passkey_title">Create a passkey in <xliff:g id="providerInfoDisplayName">%1$s</xliff:g>?</string>
+ <string name="choose_create_option_password_title">Save your password to <xliff:g id="providerInfoDisplayName">%1$s</xliff:g>?</string>
+ <string name="choose_create_option_sign_in_title">Save your sign-in info to <xliff:g id="providerInfoDisplayName">%1$s</xliff:g>?</string>
<string name="choose_sign_in_title">Use saved sign in</string>
<string name="create_passkey_at">Create passkey at</string>
- <string name="use_provider_for_all_title">Use <xliff:g id="providerInfoName">%1$s</xliff:g> for all your sign-ins?</string>
+ <string name="use_provider_for_all_title">Use <xliff:g id="providerInfoDisplayName">%1$s</xliff:g> for all your sign-ins?</string>
<string name="set_as_default">Set as default</string>
<string name="use_once">Use once</string>
+ <string name="choose_create_option_description">You can use saved <xliff:g id="type">%1$s</xliff:g> on any device. It will be saved to <xliff:g id="providerInfoDisplayName">%2$s</xliff:g> for <xliff:g id="createInfoDisplayName">%3$s</xliff:g></string>
+ <string name="more_options_title_multiple_options"><xliff:g id="providerInfoDisplayName">%1$s</xliff:g> for <xliff:g id="createInfoTitle">%2$s</xliff:g></string>
+ <string name="more_options_title_one_option"><xliff:g id="providerInfoDisplayName">%1$s</xliff:g></string>
</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 64a12cd..56fb1a9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -36,6 +36,7 @@
import com.android.credentialmanager.createflow.RequestDisplayInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.getflow.GetScreenState
+import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
// Consider repo per screen, similar to view model?
class CredentialManagerRepo(
@@ -70,11 +71,12 @@
resultReceiver?.send(BaseDialogResult.RESULT_CODE_DIALOG_CANCELED, resultData)
}
- fun onOptionSelected(providerPackageName: String, entryId: Int) {
+ fun onOptionSelected(providerPackageName: String, entryKey: String, entrySubkey: String) {
val userSelectionDialogResult = UserSelectionDialogResult(
requestInfo.token,
providerPackageName,
- entryId
+ entryKey,
+ entrySubkey
)
val resultData = Bundle()
UserSelectionDialogResult.addToBundle(userSelectionDialogResult, resultData)
@@ -83,17 +85,28 @@
fun getCredentialInitialUiState(): GetCredentialUiState {
val providerList = GetFlowUtils.toProviderList(providerList, context)
+ // TODO: covert from real requestInfo
+ val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo(
+ "Elisa Beckett",
+ "beckett-bakert@gmail.com",
+ TYPE_PUBLIC_KEY_CREDENTIAL,
+ "tribank")
return GetCredentialUiState(
providerList,
GetScreenState.CREDENTIAL_SELECTION,
+ requestDisplayInfo,
providerList.first()
)
}
fun createPasskeyInitialUiState(): CreatePasskeyUiState {
val providerList = CreateFlowUtils.toProviderList(providerList, context)
+ // TODO: covert from real requestInfo
val requestDisplayInfo = RequestDisplayInfo(
- "Elisa Beckett", "beckett-bakert@gmail.com", "TYPE_CREATE")
+ "Elisa Beckett",
+ "beckett-bakert@gmail.com",
+ TYPE_PUBLIC_KEY_CREDENTIAL,
+ "tribank")
return CreatePasskeyUiState(
providers = providerList,
currentScreenState = CreateScreenState.PASSKEY_INTRO,
@@ -125,16 +138,16 @@
Icon.createWithResource(context, R.drawable.ic_launcher_foreground))
.setCredentialEntries(
listOf<Entry>(
- newEntry(1, "elisa.beckett@gmail.com", "Elisa Backett",
- "20 passwords and 7 passkeys saved"),
- newEntry(2, "elisa.work@google.com", "Elisa Backett Work",
- "20 passwords and 7 passkeys saved"),
+ newEntry("key1", "subkey-1", "elisa.beckett@gmail.com",
+ "Elisa Backett", "20 passwords and 7 passkeys saved"),
+ newEntry("key1", "subkey-2", "elisa.work@google.com",
+ "Elisa Backett Work", "20 passwords and 7 passkeys saved"),
)
).setActionChips(
listOf<Entry>(
- newEntry(3, "Go to Settings", "",
+ newEntry("key2", "subkey-1", "Go to Settings", "",
"20 passwords and 7 passkeys saved"),
- newEntry(4, "Switch Account", "",
+ newEntry("key2", "subkey-2", "Switch Account", "",
"20 passwords and 7 passkeys saved"),
),
).build(),
@@ -144,21 +157,28 @@
Icon.createWithResource(context, R.drawable.ic_launcher_foreground))
.setCredentialEntries(
listOf<Entry>(
- newEntry(1, "elisa.beckett@dashlane.com", "Elisa Backett",
- "20 passwords and 7 passkeys saved"),
- newEntry(2, "elisa.work@dashlane.com", "Elisa Backett Work",
- "20 passwords and 7 passkeys saved"),
+ newEntry("key1", "subkey-3", "elisa.beckett@dashlane.com",
+ "Elisa Backett", "20 passwords and 7 passkeys saved"),
+ newEntry("key1", "subkey-4", "elisa.work@dashlane.com",
+ "Elisa Backett Work", "20 passwords and 7 passkeys saved"),
)
).setActionChips(
listOf<Entry>(
- newEntry(3, "Manage Accounts", "Manage your accounts in the dashlane app",
+ newEntry("key2", "subkey-3", "Manage Accounts",
+ "Manage your accounts in the dashlane app",
"20 passwords and 7 passkeys saved"),
),
).build(),
)
}
- private fun newEntry(id: Int, title: String, subtitle: String, usageData: String): Entry {
+ private fun newEntry(
+ key: String,
+ subkey: String,
+ title: String,
+ subtitle: String,
+ usageData: String
+ ): Entry {
val slice = Slice.Builder(
Entry.CREDENTIAL_MANAGER_ENTRY_URI, SliceSpec(Entry.VERSION, 1)
)
@@ -171,7 +191,8 @@
.addText(usageData, Slice.SUBTYPE_MESSAGE, listOf(Entry.HINT_SUBTITLE))
.build()
return Entry(
- id,
+ key,
+ subkey,
slice
)
}
@@ -182,7 +203,7 @@
Binder(),
CreateCredentialRequest(
// TODO: use the jetpack type and utils once defined.
- "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL",
+ TYPE_PUBLIC_KEY_CREDENTIAL,
data
),
/*isFirstUsage=*/false,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 6b503ff..e037db7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -36,7 +36,7 @@
// TODO: replace to extract from the service data structure when available
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = it.providerId,
- appDomainName = "tribank.us",
+ displayName = it.providerDisplayName,
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context)
)
@@ -59,7 +59,8 @@
?: context.getDrawable(R.drawable.ic_passkey)!!,
title = credentialEntryUi.userName.toString(),
subtitle = credentialEntryUi.displayName?.toString() ?: "Unknown display name",
- id = it.entryId,
+ entryKey = it.key,
+ entrySubkey = it.subkey,
usageData = credentialEntryUi.usageData?.toString() ?: "Unknown usageData",
)
}
@@ -79,7 +80,7 @@
// TODO: replace to extract from the service data structure when available
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = it.providerId,
- appDomainName = "tribank.us",
+ displayName = it.providerDisplayName,
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
createOptions = toCreationOptionInfoList(it.credentialEntries, context),
)
@@ -99,7 +100,8 @@
?: context.getDrawable(R.drawable.ic_passkey)!!,
title = saveEntryUi.title.toString(),
subtitle = saveEntryUi.subTitle?.toString() ?: "Unknown subtitle",
- id = it.entryId,
+ entryKey = it.key,
+ entrySubkey = it.subkey,
usageData = saveEntryUi.usageData?.toString() ?: "Unknown usageData",
)
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index e291cc2..cb2bf10 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -21,7 +21,7 @@
data class ProviderInfo(
val icon: Drawable,
val name: String,
- val appDomainName: String,
+ val displayName: String,
val credentialTypeIcon: Drawable,
val createOptions: List<CreateOptionInfo>,
)
@@ -30,7 +30,8 @@
val icon: Drawable,
val title: String,
val subtitle: String,
- val id: Int,
+ val entryKey: String,
+ val entrySubkey: String,
val usageData: String
)
@@ -38,6 +39,7 @@
val userName: String,
val displayName: String,
val type: String,
+ val appDomainName: String,
)
/**
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
index fbbc3ac..373fb80 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
@@ -39,6 +39,8 @@
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.R
+import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PASSWORD_CREDENTIAL
+import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
import com.android.credentialmanager.ui.theme.Grey100
import com.android.credentialmanager.ui.theme.Shapes
import com.android.credentialmanager.ui.theme.Typography
@@ -61,30 +63,32 @@
val uiState = viewModel.uiState
when (uiState.currentScreenState) {
CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
- onConfirm = {viewModel.onConfirmIntro()},
- onCancel = {viewModel.onCancel()},
+ onConfirm = viewModel::onConfirmIntro,
+ onCancel = viewModel::onCancel,
)
CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
providerList = uiState.providers,
- onCancel = {viewModel.onCancel()},
- onProviderSelected = {viewModel.onProviderSelected(it)}
+ onCancel = viewModel::onCancel,
+ onProviderSelected = viewModel::onProviderSelected
)
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
requestDisplayInfo = uiState.requestDisplayInfo,
providerInfo = uiState.activeEntry?.activeProvider!!,
- onOptionSelected = {viewModel.onPrimaryCreateOptionInfoSelected()},
- onCancel = {viewModel.onCancel()},
+ createOptionInfo = uiState.activeEntry.activeCreateOptionInfo,
+ onOptionSelected = viewModel::onPrimaryCreateOptionInfoSelected,
+ onConfirm = viewModel::onPrimaryCreateOptionInfoSelected,
+ onCancel = viewModel::onCancel,
multiProvider = uiState.providers.size > 1,
- onMoreOptionsSelected = {viewModel.onMoreOptionsSelected()}
+ onMoreOptionsSelected = viewModel::onMoreOptionsSelected
)
CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
providerList = uiState.providers,
- onBackButtonSelected = {viewModel.onBackButtonSelected()},
- onOptionSelected = {viewModel.onMoreOptionsRowSelected(it)}
+ onBackButtonSelected = viewModel::onBackButtonSelected,
+ onOptionSelected = viewModel::onMoreOptionsRowSelected
)
CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
providerInfo = uiState.activeEntry?.activeProvider!!,
- onDefaultOrNotSelected = {viewModel.onDefaultOrNotSelected()}
+ onDefaultOrNotSelected = viewModel::onDefaultOrNotSelected
)
}
},
@@ -294,7 +298,7 @@
) {
Column() {
Text(
- text = stringResource(R.string.use_provider_for_all_title, providerInfo.name),
+ text = stringResource(R.string.use_provider_for_all_title, providerInfo.displayName),
style = Typography.subtitle1,
modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally)
)
@@ -340,7 +344,7 @@
shape = Shapes.large
) {
Text(
- text = providerInfo.name,
+ text = providerInfo.displayName,
style = Typography.button,
modifier = Modifier.padding(vertical = 18.dp)
)
@@ -392,7 +396,9 @@
fun CreationSelectionCard(
requestDisplayInfo: RequestDisplayInfo,
providerInfo: ProviderInfo,
+ createOptionInfo: CreateOptionInfo,
onOptionSelected: () -> Unit,
+ onConfirm: () -> Unit,
onCancel: () -> Unit,
multiProvider: Boolean,
onMoreOptionsSelected: () -> Unit,
@@ -405,21 +411,39 @@
bitmap = providerInfo.credentialTypeIcon.toBitmap().asImageBitmap(),
contentDescription = null,
tint = Color.Unspecified,
- modifier = Modifier.align(alignment = Alignment.CenterHorizontally).padding(top = 24.dp)
+ modifier = Modifier.align(alignment = Alignment.CenterHorizontally).padding(all = 24.dp)
)
Text(
- text = "${stringResource(R.string.choose_create_option_title)} ${providerInfo.name}",
+ text = when (requestDisplayInfo.type) {
+ TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.choose_create_option_passkey_title,
+ providerInfo.displayName)
+ TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.choose_create_option_password_title,
+ providerInfo.displayName)
+ else -> stringResource(R.string.choose_create_option_sign_in_title,
+ providerInfo.displayName)
+ },
style = Typography.subtitle1,
- modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally)
+ modifier = Modifier.padding(horizontal = 24.dp)
+ .align(alignment = Alignment.CenterHorizontally),
+ textAlign = TextAlign.Center,
)
Text(
- text = providerInfo.appDomainName,
+ text = requestDisplayInfo.appDomainName,
style = Typography.body2,
- modifier = Modifier.padding(horizontal = 28.dp)
+ modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
)
- Divider(
- thickness = 24.dp,
- color = Color.Transparent
+ Text(
+ text = stringResource(
+ R.string.choose_create_option_description,
+ when (requestDisplayInfo.type) {
+ TYPE_PUBLIC_KEY_CREDENTIAL -> "passkeys"
+ TYPE_PASSWORD_CREDENTIAL -> "passwords"
+ else -> "sign-ins"
+ },
+ providerInfo.displayName,
+ createOptionInfo.title),
+ style = Typography.body1,
+ modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally)
)
Card(
shape = Shapes.medium,
@@ -446,10 +470,17 @@
color = Color.Transparent
)
Row(
- horizontalArrangement = Arrangement.Start,
+ horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
) {
- CancelButton(stringResource(R.string.string_cancel), onCancel)
+ CancelButton(
+ stringResource(R.string.string_cancel),
+ onclick = onCancel
+ )
+ ConfirmButton(
+ stringResource(R.string.string_continue),
+ onclick = onConfirm
+ )
}
Divider(
thickness = 18.dp,
@@ -462,47 +493,13 @@
@ExperimentalMaterialApi
@Composable
-fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (Int) -> Unit) {
- Chip(
- modifier = Modifier.fillMaxWidth(),
- onClick = {onOptionSelected(createOptionInfo.id)},
- leadingIcon = {
- Image(modifier = Modifier.size(24.dp, 24.dp).padding(start = 10.dp),
- bitmap = createOptionInfo.icon.toBitmap().asImageBitmap(),
- // painter = painterResource(R.drawable.ic_passkey),
- // TODO: add description.
- contentDescription = "")
- },
- colors = ChipDefaults.chipColors(
- backgroundColor = Grey100,
- leadingIconContentColor = Grey100
- ),
- shape = Shapes.large
- ) {
- Column() {
- Text(
- text = createOptionInfo.title,
- style = Typography.h6,
- modifier = Modifier.padding(top = 16.dp)
- )
- Text(
- text = createOptionInfo.subtitle,
- style = Typography.body2,
- modifier = Modifier.padding(bottom = 16.dp)
- )
- }
- }
-}
-
-@ExperimentalMaterialApi
-@Composable
fun PrimaryCreateOptionRow(
requestDisplayInfo: RequestDisplayInfo,
onOptionSelected: () -> Unit
) {
Chip(
modifier = Modifier.fillMaxWidth(),
- onClick = {onOptionSelected()},
+ onClick = onOptionSelected,
// TODO: Add an icon generated by provider according to requestDisplayInfo type
colors = ChipDefaults.chipColors(
backgroundColor = Grey100,
@@ -550,8 +547,12 @@
) {
Column() {
Text(
- text = if (providerInfo.createOptions.size > 1)
- {providerInfo.name + " for " + createOptionInfo.title} else { providerInfo.name},
+ text =
+ if (providerInfo.createOptions.size > 1)
+ {stringResource(R.string.more_options_title_multiple_options,
+ providerInfo.displayName, createOptionInfo.title)} else {
+ stringResource(R.string.more_options_title_one_option,
+ providerInfo.displayName)},
style = Typography.h6,
modifier = Modifier.padding(top = 16.dp)
)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
index 38486e2c..615da4e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
@@ -73,11 +73,15 @@
)
}
- fun onCreateOptionSelected(createOptionId: Int) {
- Log.d("Account Selector", "Option selected for creation: $createOptionId")
+ fun onCreateOptionSelected(entryKey: String, entrySubkey: String) {
+ Log.d(
+ "Account Selector",
+ "Option selected for creation: {key = $entryKey, subkey = $entrySubkey}"
+ )
CredentialManagerRepo.getInstance().onOptionSelected(
uiState.activeEntry?.activeProvider!!.name,
- createOptionId
+ entryKey,
+ entrySubkey
)
dialogResult.value = DialogResult(
ResultState.COMPLETE,
@@ -122,13 +126,21 @@
}
fun onPrimaryCreateOptionInfoSelected() {
- var createOptionId = uiState.activeEntry?.activeCreateOptionInfo?.id
- Log.d("Account Selector", "Option selected for creation: $createOptionId")
- if (createOptionId != null) {
+ var createOptionEntryKey = uiState.activeEntry?.activeCreateOptionInfo?.entryKey
+ var createOptionEntrySubkey = uiState.activeEntry?.activeCreateOptionInfo?.entrySubkey
+ Log.d(
+ "Account Selector",
+ "Option selected for creation: " +
+ "{key = $createOptionEntryKey, subkey = $createOptionEntrySubkey}"
+ )
+ if (createOptionEntryKey != null && createOptionEntrySubkey != null) {
CredentialManagerRepo.getInstance().onOptionSelected(
uiState.activeEntry?.activeProvider!!.name,
- createOptionId
+ createOptionEntryKey,
+ createOptionEntrySubkey
)
+ } else {
+ TODO("Gracefully handle illegal state.")
}
dialogResult.value = DialogResult(
ResultState.COMPLETE,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 48c67bb..e3398c0 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -66,11 +66,12 @@
val uiState = viewModel.uiState
when (uiState.currentScreenState) {
GetScreenState.CREDENTIAL_SELECTION -> CredentialSelectionCard(
+ requestDisplayInfo = uiState.requestDisplayInfo,
providerInfo = uiState.selectedProvider!!,
- onCancel = {viewModel.onCancel()},
- onOptionSelected = {viewModel.onCredentailSelected(it)},
+ onCancel = viewModel::onCancel,
+ onOptionSelected = viewModel::onCredentailSelected,
multiProvider = uiState.providers.size > 1,
- onMoreOptionSelected = {viewModel.onMoreOptionSelected()},
+ onMoreOptionSelected = viewModel::onMoreOptionSelected,
)
}
},
@@ -87,8 +88,9 @@
@ExperimentalMaterialApi
@Composable
fun CredentialSelectionCard(
+ requestDisplayInfo: RequestDisplayInfo,
providerInfo: ProviderInfo,
- onOptionSelected: (Int) -> Unit,
+ onOptionSelected: (String, String) -> Unit,
onCancel: () -> Unit,
multiProvider: Boolean,
onMoreOptionSelected: () -> Unit,
@@ -111,7 +113,7 @@
.align(alignment = Alignment.CenterHorizontally)
)
Text(
- text = providerInfo.appDomainName,
+ text = requestDisplayInfo.appDomainName,
style = Typography.body2,
modifier = Modifier.padding(horizontal = 28.dp)
)
@@ -163,11 +165,11 @@
@Composable
fun CredentialOptionRow(
credentialOptionInfo: CredentialOptionInfo,
- onOptionSelected: (Int) -> Unit
+ onOptionSelected: (String, String) -> Unit,
) {
Chip(
modifier = Modifier.fillMaxWidth(),
- onClick = {onOptionSelected(credentialOptionInfo.id)},
+ onClick = {onOptionSelected(credentialOptionInfo.entryKey, credentialOptionInfo.entrySubkey)},
leadingIcon = {
Image(modifier = Modifier.size(24.dp, 24.dp).padding(start = 10.dp),
bitmap = credentialOptionInfo.icon.toBitmap().asImageBitmap(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 33858f5..7b6c30a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -30,6 +30,7 @@
data class GetCredentialUiState(
val providers: List<ProviderInfo>,
val currentScreenState: GetScreenState,
+ val requestDisplayInfo: RequestDisplayInfo,
val selectedProvider: ProviderInfo? = null,
)
@@ -48,11 +49,12 @@
return dialogResult
}
- fun onCredentailSelected(credentialId: Int) {
- Log.d("Account Selector", "credential selected: $credentialId")
+ fun onCredentailSelected(entryKey: String, entrySubkey: String) {
+ Log.d("Account Selector", "credential selected: {key=$entryKey,subkey=$entrySubkey}")
CredentialManagerRepo.getInstance().onOptionSelected(
uiState.selectedProvider!!.name,
- credentialId
+ entryKey,
+ entrySubkey
)
dialogResult.value = DialogResult(
ResultState.COMPLETE,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index a39b211..b6ecd37 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -21,7 +21,7 @@
data class ProviderInfo(
val icon: Drawable,
val name: String,
- val appDomainName: String,
+ val displayName: String,
val credentialTypeIcon: Drawable,
val credentialOptions: List<CredentialOptionInfo>,
)
@@ -30,10 +30,18 @@
val icon: Drawable,
val title: String,
val subtitle: String,
- val id: Int,
+ val entryKey: String,
+ val entrySubkey: String,
val usageData: String
)
+data class RequestDisplayInfo(
+ val userName: String,
+ val displayName: String,
+ val type: String,
+ val appDomainName: String,
+)
+
/** The name of the current screen. */
enum class GetScreenState {
CREDENTIAL_SELECTION,
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
index 68c63da..4fb77d7 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -18,9 +18,8 @@
ext {
spa_min_sdk = 21
spa_target_sdk = 33
- jetpack_compose_version = '1.2.0-alpha04'
+ jetpack_compose_version = '1.3.0'
jetpack_compose_compiler_version = '1.3.2'
- jetpack_compose_material3_version = '1.0.0-alpha06'
}
}
plugins {
diff --git a/packages/SettingsLib/Spa/gallery/build.gradle b/packages/SettingsLib/Spa/gallery/build.gradle
index c1ce7d9..20dd707 100644
--- a/packages/SettingsLib/Spa/gallery/build.gradle
+++ b/packages/SettingsLib/Spa/gallery/build.gradle
@@ -54,11 +54,6 @@
composeOptions {
kotlinCompilerExtensionVersion jetpack_compose_compiler_version
}
- packagingOptions {
- resources {
- excludes += '/META-INF/{AL2.0,LGPL2.1}'
- }
- }
}
dependencies {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
index e09ebda..b38178b 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
@@ -17,7 +17,10 @@
package com.android.settingslib.spa.gallery.page
import android.os.Bundle
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
@@ -48,9 +51,11 @@
@Composable
override fun Page(arguments: Bundle?) {
- SettingsScaffold(title = TITLE) {
- SettingsPager(listOf("Personal", "Work")) {
- PlaceholderTitle("Page $it")
+ SettingsScaffold(title = TITLE) { paddingValues ->
+ Box(Modifier.padding(paddingValues)) {
+ SettingsPager(listOf("Personal", "Work")) {
+ PlaceholderTitle("Page $it")
+ }
}
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index a2a913f..fa8d51c 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -27,6 +27,7 @@
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.EntrySearchData
+import com.android.settingslib.spa.framework.common.EntryStatusData
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -104,6 +105,7 @@
entryList.add(
createEntry(EntryEnum.DISABLED_PREFERENCE)
.setIsAllowSearch(true)
+ .setHasMutableStatus(true)
.setMacro {
spaLogger.message(TAG, "create macro for ${EntryEnum.DISABLED_PREFERENCE}")
SimplePreferenceMacro(
@@ -113,14 +115,17 @@
icon = Icons.Outlined.DisabledByDefault,
)
}
+ .setStatusDataFn { EntryStatusData(isDisabled = true) }
.build()
)
entryList.add(
createEntry(EntryEnum.ASYNC_SUMMARY_PREFERENCE)
.setIsAllowSearch(true)
+ .setHasMutableStatus(true)
.setSearchDataFn {
EntrySearchData(title = ASYNC_PREFERENCE_TITLE)
}
+ .setStatusDataFn { EntryStatusData(isDisabled = false) }
.setUiLayoutFn {
val model = PreferencePageModel.create()
val asyncSummary = remember { model.getAsyncSummary() }
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index c587411..2820ed7 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -51,16 +51,11 @@
composeOptions {
kotlinCompilerExtensionVersion jetpack_compose_compiler_version
}
- packagingOptions {
- resources {
- excludes += '/META-INF/{AL2.0,LGPL2.1}'
- }
- }
}
dependencies {
api "androidx.appcompat:appcompat:1.7.0-alpha01"
- api "androidx.compose.material3:material3:$jetpack_compose_material3_version"
+ api "androidx.compose.material3:material3:1.1.0-alpha01"
api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index 89daeb1..d3efaa7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -35,6 +35,7 @@
import androidx.navigation.compose.rememberNavController
import com.android.settingslib.spa.R
import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.LocalNavController
@@ -44,7 +45,6 @@
import com.android.settingslib.spa.framework.util.navRoute
private const val TAG = "BrowseActivity"
-private const val NULL_PAGE_NAME = "NULL"
/**
* The Activity to render ALL SPA pages, and handles jumps between SPA pages.
@@ -81,9 +81,10 @@
private fun MainContent() {
val sppRepository by spaEnvironment.pageProviderRepository
val navController = rememberNavController()
+ val nullPage = SettingsPage.createNull()
CompositionLocalProvider(navController.localNavController()) {
- NavHost(navController, NULL_PAGE_NAME) {
- composable(NULL_PAGE_NAME) {}
+ NavHost(navController, nullPage.sppName) {
+ composable(nullPage.sppName) {}
for (spp in sppRepository.getAllProviders()) {
composable(
route = spp.name + spp.parameter.navRoute(),
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt
index d631708..38f41bc 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt
@@ -42,9 +42,10 @@
* For gallery, AuthorityPath = com.android.spa.gallery.provider
* For Settings, AuthorityPath = com.android.settings.spa.provider
* Some examples:
- * $ adb shell content query --uri content://<AuthorityPath>/search_sitemap
* $ adb shell content query --uri content://<AuthorityPath>/search_static
* $ adb shell content query --uri content://<AuthorityPath>/search_dynamic
+ * $ adb shell content query --uri content://<AuthorityPath>/search_mutable_status
+ * $ adb shell content query --uri content://<AuthorityPath>/search_immutable_status
*/
open class EntryProvider : ContentProvider() {
private val spaEnvironment get() = SpaEnvironmentFactory.instance
@@ -81,9 +82,10 @@
override fun attachInfo(context: Context?, info: ProviderInfo?) {
if (info != null) {
- QueryEnum.SEARCH_SITEMAP_QUERY.addUri(uriMatcher, info.authority)
QueryEnum.SEARCH_STATIC_DATA_QUERY.addUri(uriMatcher, info.authority)
QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.addUri(uriMatcher, info.authority)
+ QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.addUri(uriMatcher, info.authority)
+ QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.addUri(uriMatcher, info.authority)
}
super.attachInfo(context, info)
}
@@ -97,9 +99,12 @@
): Cursor? {
return try {
when (uriMatcher.match(uri)) {
- QueryEnum.SEARCH_SITEMAP_QUERY.queryMatchCode -> querySearchSitemap()
QueryEnum.SEARCH_STATIC_DATA_QUERY.queryMatchCode -> querySearchStaticData()
QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.queryMatchCode -> querySearchDynamicData()
+ QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.queryMatchCode ->
+ querySearchMutableStatusData()
+ QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.queryMatchCode ->
+ querySearchImmutableStatusData()
else -> throw UnsupportedOperationException("Unknown Uri $uri")
}
} catch (e: UnsupportedOperationException) {
@@ -110,18 +115,22 @@
}
}
- private fun querySearchSitemap(): Cursor {
+ private fun querySearchImmutableStatusData(): Cursor {
val entryRepository by spaEnvironment.entryRepository
- val cursor = MatrixCursor(QueryEnum.SEARCH_SITEMAP_QUERY.getColumns())
+ val cursor = MatrixCursor(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.getColumns())
for (entry in entryRepository.getAllEntries()) {
- if (!entry.isAllowSearch) continue
- val intent = entry.containerPage()
- .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id)
- ?: Intent()
- cursor.newRow()
- .add(ColumnEnum.ENTRY_ID.id, entry.id)
- .add(ColumnEnum.ENTRY_HIERARCHY_PATH.id, entryRepository.getEntryPath(entry.id))
- .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME))
+ if (!entry.isAllowSearch || entry.mutableStatus) continue
+ fetchStatusData(entry, cursor)
+ }
+ return cursor
+ }
+
+ private fun querySearchMutableStatusData(): Cursor {
+ val entryRepository by spaEnvironment.entryRepository
+ val cursor = MatrixCursor(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.getColumns())
+ for (entry in entryRepository.getAllEntries()) {
+ if (!entry.isAllowSearch || !entry.mutableStatus) continue
+ fetchStatusData(entry, cursor)
}
return cursor
}
@@ -147,14 +156,28 @@
}
private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
+ val entryRepository by spaEnvironment.entryRepository
+ val browseActivityClass = spaEnvironment.browseActivityClass
+
// Fetch search data. We can add runtime arguments later if necessary
- val searchData = entry.getSearchData()
+ val searchData = entry.getSearchData() ?: return
+ val intent = entry.containerPage()
+ .createBrowseIntent(context, browseActivityClass, entry.id)
+ ?: Intent()
cursor.newRow()
.add(ColumnEnum.ENTRY_ID.id, entry.id)
- .add(ColumnEnum.ENTRY_TITLE.id, searchData?.title ?: "")
- .add(
- ColumnEnum.ENTRY_SEARCH_KEYWORD.id,
- searchData?.keyword ?: emptyList<String>()
- )
+ .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME))
+ .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
+ .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
+ .add(ColumnEnum.SEARCH_PATH.id,
+ entryRepository.getEntryPathWithTitle(entry.id, searchData.title))
+ }
+
+ private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
+ // Fetch status data. We can add runtime arguments later if necessary
+ val statusData = entry.getStatusData() ?: return
+ cursor.newRow()
+ .add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.SEARCH_STATUS_DISABLED.id, statusData.isDisabled)
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryMacro.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryMacro.kt
index 9ec0c01..b3571a1 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryMacro.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryMacro.kt
@@ -26,4 +26,5 @@
@Composable
fun UiLayout() {}
fun getSearchData(): EntrySearchData? = null
+ fun getStatusData(): EntryStatusData? = null
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntrySearchData.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntrySearchData.kt
index 9b262af..9bc620f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntrySearchData.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntrySearchData.kt
@@ -22,12 +22,4 @@
data class EntrySearchData(
val title: String = "",
val keyword: List<String> = emptyList(),
-) {
- fun format(): String {
- val content = listOf(
- "search_title = $title",
- "search_keyword = $keyword",
- )
- return content.joinToString("\n")
- }
-}
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryStatusData.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryStatusData.kt
new file mode 100644
index 0000000..3e9dd3b
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/EntryStatusData.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.settingslib.spa.framework.common
+
+/**
+ * Defines the status data of one Settings entry, which could be changed frequently.
+ */
+data class EntryStatusData(
+ val isDisabled: Boolean = false,
+ val isSwitchOff: Boolean = false,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt
index 0707429..121c07f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt
@@ -40,8 +40,10 @@
ENTRY_START_ADB("entryStartAdb"),
// Columns related to search
- ENTRY_TITLE("entryTitle"),
- ENTRY_SEARCH_KEYWORD("entrySearchKw"),
+ SEARCH_TITLE("searchTitle"),
+ SEARCH_KEYWORD("searchKw"),
+ SEARCH_PATH("searchPath"),
+ SEARCH_STATUS_DISABLED("searchDisabled"),
}
/**
@@ -83,32 +85,42 @@
ColumnEnum.ENTRY_NAME,
ColumnEnum.ENTRY_ROUTE,
ColumnEnum.ENTRY_INTENT_URI,
+ ColumnEnum.ENTRY_HIERARCHY_PATH,
)
),
- // Search related queries
- SEARCH_SITEMAP_QUERY(
- "search_sitemap", 300,
- listOf(
- ColumnEnum.ENTRY_ID,
- ColumnEnum.ENTRY_HIERARCHY_PATH,
- ColumnEnum.ENTRY_INTENT_URI,
- )
- ),
SEARCH_STATIC_DATA_QUERY(
"search_static", 301,
listOf(
ColumnEnum.ENTRY_ID,
- ColumnEnum.ENTRY_TITLE,
- ColumnEnum.ENTRY_SEARCH_KEYWORD,
+ ColumnEnum.ENTRY_INTENT_URI,
+ ColumnEnum.SEARCH_TITLE,
+ ColumnEnum.SEARCH_KEYWORD,
+ ColumnEnum.SEARCH_PATH,
)
),
SEARCH_DYNAMIC_DATA_QUERY(
"search_dynamic", 302,
listOf(
ColumnEnum.ENTRY_ID,
- ColumnEnum.ENTRY_TITLE,
- ColumnEnum.ENTRY_SEARCH_KEYWORD,
+ ColumnEnum.ENTRY_INTENT_URI,
+ ColumnEnum.SEARCH_TITLE,
+ ColumnEnum.SEARCH_KEYWORD,
+ ColumnEnum.SEARCH_PATH,
+ )
+ ),
+ SEARCH_IMMUTABLE_STATUS_DATA_QUERY(
+ "search_immutable_status", 303,
+ listOf(
+ ColumnEnum.ENTRY_ID,
+ ColumnEnum.SEARCH_STATUS_DISABLED,
+ )
+ ),
+ SEARCH_MUTABLE_STATUS_DATA_QUERY(
+ "search_mutable_status", 304,
+ listOf(
+ ColumnEnum.ENTRY_ID,
+ ColumnEnum.SEARCH_STATUS_DISABLED,
)
),
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index fb42f01..224fe1d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -65,8 +65,14 @@
* ========================================
*/
val isAllowSearch: Boolean = false,
+
+ // Indicate whether the search indexing data of entry is dynamic.
val isSearchDataDynamic: Boolean = false,
+ // Indicate whether the status of entry is mutable.
+ // If so, for instance, we'll reindex its status for search.
+ val mutableStatus: Boolean = false,
+
/**
* ========================================
* Defines entry APIs to get data here.
@@ -74,8 +80,14 @@
*/
/**
- * API to get Search related data for this entry.
- * Returns null if this entry is not available for the search at the moment.
+ * API to get the status data of the entry, such as isDisabled / isSwitchOff.
+ * Returns null if this entry do NOT have any status.
+ */
+ private val statusDataImpl: (arguments: Bundle?) -> EntryStatusData? = { null },
+
+ /**
+ * API to get Search indexing data for this entry, such as title / keyword.
+ * Returns null if this entry do NOT support search.
*/
private val searchDataImpl: (arguments: Bundle?) -> EntrySearchData? = { null },
@@ -87,21 +99,6 @@
*/
private val uiLayoutImpl: (@Composable (arguments: Bundle?) -> Unit) = {},
) {
- fun formatContent(): String {
- val content = listOf(
- "id = $id",
- "owner = ${owner.formatDisplayTitle()}",
- "linkFrom = ${fromPage?.formatDisplayTitle()}",
- "linkTo = ${toPage?.formatDisplayTitle()}",
- "${getSearchData()?.format()}",
- )
- return content.joinToString("\n")
- }
-
- fun displayTitle(): String {
- return "${owner.displayName}:$displayName"
- }
-
fun containerPage(): SettingsPage {
// The Container page of the entry, which is the from-page or
// the owner-page if from-page is unset.
@@ -116,6 +113,10 @@
return arguments
}
+ fun getStatusData(runtimeArguments: Bundle? = null): EntryStatusData? {
+ return statusDataImpl(fullArgument(runtimeArguments))
+ }
+
fun getSearchData(runtimeArguments: Bundle? = null): EntrySearchData? {
return searchDataImpl(fullArgument(runtimeArguments))
}
@@ -151,8 +152,10 @@
// Attributes
private var isAllowSearch: Boolean = false
private var isSearchDataDynamic: Boolean = false
+ private var mutableStatus: Boolean = false
// Functions
+ private var statusDataFn: (arguments: Bundle?) -> EntryStatusData? = { null }
private var searchDataFn: (arguments: Bundle?) -> EntrySearchData? = { null }
private var uiLayoutFn: (@Composable (arguments: Bundle?) -> Unit) = { }
@@ -170,8 +173,10 @@
// attributes
isAllowSearch = isAllowSearch,
isSearchDataDynamic = isSearchDataDynamic,
+ mutableStatus = mutableStatus,
// functions
+ statusDataImpl = statusDataFn,
searchDataImpl = searchDataFn,
uiLayoutImpl = uiLayoutFn,
)
@@ -201,7 +206,13 @@
return this
}
+ fun setHasMutableStatus(hasMutableStatus: Boolean): SettingsEntryBuilder {
+ this.mutableStatus = hasMutableStatus
+ return this
+ }
+
fun setMacro(fn: (arguments: Bundle?) -> EntryMacro): SettingsEntryBuilder {
+ setStatusDataFn { fn(it).getStatusData() }
setSearchDataFn { fn(it).getSearchData() }
setUiLayoutFn {
val macro = remember { fn(it) }
@@ -210,6 +221,11 @@
return this
}
+ fun setStatusDataFn(fn: (arguments: Bundle?) -> EntryStatusData?): SettingsEntryBuilder {
+ this.statusDataFn = fn
+ return this
+ }
+
fun setSearchDataFn(fn: (arguments: Bundle?) -> EntrySearchData?): SettingsEntryBuilder {
this.searchDataFn = fn
return this
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
index ea20233..e63e4c9 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -21,10 +21,13 @@
private const val TAG = "EntryRepository"
private const val MAX_ENTRY_SIZE = 5000
+private const val MAX_ENTRY_DEPTH = 10
data class SettingsPageWithEntry(
val page: SettingsPage,
val entries: List<SettingsEntry>,
+ // The inject entry, which to-page is current page.
+ val injectEntry: SettingsEntry,
)
/**
@@ -42,9 +45,11 @@
entryMap = mutableMapOf()
pageWithEntryMap = mutableMapOf()
+ val nullPage = SettingsPage.createNull()
val entryQueue = LinkedList<SettingsEntry>()
for (page in sppRepository.getAllRootPages()) {
- val rootEntry = SettingsEntryBuilder.createRoot(owner = page).build()
+ val rootEntry =
+ SettingsEntryBuilder.createRoot(owner = page).setLink(fromPage = nullPage).build()
if (!entryMap.containsKey(rootEntry.id)) {
entryQueue.push(rootEntry)
entryMap.put(rootEntry.id, rootEntry)
@@ -57,7 +62,11 @@
if (page == null || pageWithEntryMap.containsKey(page.id)) continue
val spp = sppRepository.getProviderOrNull(page.sppName) ?: continue
val newEntries = spp.buildEntry(page.arguments)
- pageWithEntryMap[page.id] = SettingsPageWithEntry(page, newEntries)
+ pageWithEntryMap[page.id] = SettingsPageWithEntry(
+ page = page,
+ entries = newEntries,
+ injectEntry = entry
+ )
for (newEntry in newEntries) {
if (!entryMap.containsKey(newEntry.id)) {
entryQueue.push(newEntry)
@@ -88,7 +97,29 @@
return entryMap[entryId]
}
- fun getEntryPath(entryId: String): String {
- return "TODO(path_of_$entryId)"
+ private fun getEntryPath(entryId: String): List<SettingsEntry> {
+ val entryPath = ArrayList<SettingsEntry>()
+ var currentEntry = entryMap[entryId]
+ while (currentEntry != null && entryPath.size < MAX_ENTRY_DEPTH) {
+ entryPath.add(currentEntry)
+ val currentPage = currentEntry.containerPage()
+ currentEntry = pageWithEntryMap[currentPage.id]?.injectEntry
+ }
+ return entryPath
+ }
+
+ fun getEntryPathWithDisplayName(entryId: String): List<String> {
+ val entryPath = getEntryPath(entryId)
+ return entryPath.map { it.displayName }
+ }
+
+ fun getEntryPathWithTitle(entryId: String, defaultTitle: String): List<String> {
+ val entryPath = getEntryPath(entryId)
+ return entryPath.map {
+ if (it.toPage == null)
+ defaultTitle
+ else
+ it.toPage.getTitle()!!
+ }
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
index 07df96e..2fa9229 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
@@ -27,6 +27,8 @@
import com.android.settingslib.spa.framework.util.navLink
import com.android.settingslib.spa.framework.util.normalize
+private const val NULL_PAGE_NAME = "NULL"
+
/**
* Defines data to identify a Settings page.
*/
@@ -47,6 +49,10 @@
val arguments: Bundle? = null,
) {
companion object {
+ fun createNull(): SettingsPage {
+ return create(NULL_PAGE_NAME)
+ }
+
fun create(
name: String,
displayName: String? = null,
@@ -78,16 +84,6 @@
return sppName == SppName
}
- fun formatArguments(): String {
- val normArguments = parameter.normalize(arguments)
- if (normArguments == null || normArguments.isEmpty) return "[No arguments]"
- return normArguments.toString().removeRange(0, 6)
- }
-
- fun formatDisplayTitle(): String {
- return "$displayName ${formatArguments()}"
- }
-
fun buildRoute(): String {
return sppName + parameter.navLink(arguments)
}
@@ -99,12 +95,17 @@
return false
}
+ fun getTitle(): String? {
+ val sppRepository by SpaEnvironmentFactory.instance.pageProviderRepository
+ return sppRepository.getProviderOrNull(sppName)?.getTitle(arguments)
+ }
+
fun enterPage() {
SpaEnvironmentFactory.instance.logger.event(
id,
LogEvent.PAGE_ENTER,
category = LogCategory.FRAMEWORK,
- details = formatDisplayTitle()
+ details = displayName,
)
}
@@ -113,7 +114,7 @@
id,
LogEvent.PAGE_LEAVE,
category = LogCategory.FRAMEWORK,
- details = formatDisplayTitle()
+ details = displayName,
)
}
@@ -149,6 +150,7 @@
fun isBrowsable(context: Context?, browseActivityClass: Class<out Activity>?): Boolean {
return context != null &&
browseActivityClass != null &&
+ !isCreateBy(NULL_PAGE_NAME) &&
!hasRuntimeParam()
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
index e8a4411..f8963b2 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
@@ -41,6 +41,8 @@
fun Page(arguments: Bundle?)
fun buildEntry(arguments: Bundle?): List<SettingsEntry> = emptyList()
+
+ fun getTitle(arguments: Bundle?): String = displayName ?: name
}
fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/FlowExt.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/FlowExt.kt
new file mode 100644
index 0000000..dbf8836
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/FlowExt.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright 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.settingslib.spa.framework.compose
+
+import android.annotation.SuppressLint
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.produceState
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.withContext
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+
+/**
+ * *************************************************************************************************
+ * This file was forked from AndroidX:
+ * lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/FlowExt.kt
+ * TODO: Replace with AndroidX when it's usable.
+ */
+
+/**
+ * Collects values from this [StateFlow] and represents its latest value via [State] in a
+ * lifecycle-aware manner.
+ *
+ * The [StateFlow.value] is used as an initial value. Every time there would be new value posted
+ * into the [StateFlow] the returned [State] will be updated causing recomposition of every
+ * [State.value] usage whenever the [lifecycleOwner]'s lifecycle is at least [minActiveState].
+ *
+ * This [StateFlow] is collected every time the [lifecycleOwner]'s lifecycle reaches the
+ * [minActiveState] Lifecycle state. The collection stops when the [lifecycleOwner]'s lifecycle
+ * falls below [minActiveState].
+ *
+ * @sample androidx.lifecycle.compose.samples.StateFlowCollectAsStateWithLifecycle
+ *
+ * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
+ * parameter will throw an [IllegalArgumentException].
+ *
+ * @param lifecycleOwner [LifecycleOwner] whose `lifecycle` is used to restart collecting `this`
+ * flow.
+ * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
+ * collection will stop if the lifecycle falls below that state, and will restart if it's in that
+ * state again.
+ * @param context [CoroutineContext] to use for collecting.
+ */
+@SuppressLint("StateFlowValueCalledInComposition")
+@Composable
+fun <T> StateFlow<T>.collectAsStateWithLifecycle(
+ lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
+ minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
+ context: CoroutineContext = EmptyCoroutineContext
+): State<T> = collectAsStateWithLifecycle(
+ initialValue = this.value,
+ lifecycle = lifecycleOwner.lifecycle,
+ minActiveState = minActiveState,
+ context = context
+)
+
+/**
+ * Collects values from this [StateFlow] and represents its latest value via [State] in a
+ * lifecycle-aware manner.
+ *
+ * The [StateFlow.value] is used as an initial value. Every time there would be new value posted
+ * into the [StateFlow] the returned [State] will be updated causing recomposition of every
+ * [State.value] usage whenever the [lifecycle] is at least [minActiveState].
+ *
+ * This [StateFlow] is collected every time [lifecycle] reaches the [minActiveState] Lifecycle
+ * state. The collection stops when [lifecycle] falls below [minActiveState].
+ *
+ * @sample androidx.lifecycle.compose.samples.StateFlowCollectAsStateWithLifecycle
+ *
+ * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
+ * parameter will throw an [IllegalArgumentException].
+ *
+ * @param lifecycle [Lifecycle] used to restart collecting `this` flow.
+ * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
+ * collection will stop if the lifecycle falls below that state, and will restart if it's in that
+ * state again.
+ * @param context [CoroutineContext] to use for collecting.
+ */
+@SuppressLint("StateFlowValueCalledInComposition")
+@Composable
+fun <T> StateFlow<T>.collectAsStateWithLifecycle(
+ lifecycle: Lifecycle,
+ minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
+ context: CoroutineContext = EmptyCoroutineContext
+): State<T> = collectAsStateWithLifecycle(
+ initialValue = this.value,
+ lifecycle = lifecycle,
+ minActiveState = minActiveState,
+ context = context
+)
+
+/**
+ * Collects values from this [Flow] and represents its latest value via [State] in a
+ * lifecycle-aware manner.
+ *
+ * Every time there would be new value posted into the [Flow] the returned [State] will be updated
+ * causing recomposition of every [State.value] usage whenever the [lifecycleOwner]'s lifecycle is
+ * at least [minActiveState].
+ *
+ * This [Flow] is collected every time the [lifecycleOwner]'s lifecycle reaches the [minActiveState]
+ * Lifecycle state. The collection stops when the [lifecycleOwner]'s lifecycle falls below
+ * [minActiveState].
+ *
+ * @sample androidx.lifecycle.compose.samples.FlowCollectAsStateWithLifecycle
+ *
+ * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
+ * parameter will throw an [IllegalArgumentException].
+ *
+ * @param initialValue The initial value given to the returned [State.value].
+ * @param lifecycleOwner [LifecycleOwner] whose `lifecycle` is used to restart collecting `this`
+ * flow.
+ * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
+ * collection will stop if the lifecycle falls below that state, and will restart if it's in that
+ * state again.
+ * @param context [CoroutineContext] to use for collecting.
+ */
+@Composable
+fun <T> Flow<T>.collectAsStateWithLifecycle(
+ initialValue: T,
+ lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
+ minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
+ context: CoroutineContext = EmptyCoroutineContext
+): State<T> = collectAsStateWithLifecycle(
+ initialValue = initialValue,
+ lifecycle = lifecycleOwner.lifecycle,
+ minActiveState = minActiveState,
+ context = context
+)
+
+/**
+ * Collects values from this [Flow] and represents its latest value via [State] in a
+ * lifecycle-aware manner.
+ *
+ * Every time there would be new value posted into the [Flow] the returned [State] will be updated
+ * causing recomposition of every [State.value] usage whenever the [lifecycle] is at
+ * least [minActiveState].
+ *
+ * This [Flow] is collected every time [lifecycle] reaches the [minActiveState] Lifecycle
+ * state. The collection stops when [lifecycle] falls below [minActiveState].
+ *
+ * @sample androidx.lifecycle.compose.samples.FlowCollectAsStateWithLifecycle
+ *
+ * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
+ * parameter will throw an [IllegalArgumentException].
+ *
+ * @param initialValue The initial value given to the returned [State.value].
+ * @param lifecycle [Lifecycle] used to restart collecting `this` flow.
+ * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
+ * collection will stop if the lifecycle falls below that state, and will restart if it's in that
+ * state again.
+ * @param context [CoroutineContext] to use for collecting.
+ */
+@Composable
+fun <T> Flow<T>.collectAsStateWithLifecycle(
+ initialValue: T,
+ lifecycle: Lifecycle,
+ minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
+ context: CoroutineContext = EmptyCoroutineContext
+): State<T> {
+ return produceState(initialValue, this, lifecycle, minActiveState, context) {
+ lifecycle.repeatOnLifecycle(minActiveState) {
+ if (context == EmptyCoroutineContext) {
+ this@collectAsStateWithLifecycle.collect { this@produceState.value = it }
+ } else withContext(context) {
+ this@collectAsStateWithLifecycle.collect { this@produceState.value = it }
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
new file mode 100644
index 0000000..8d0313f
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.settingslib.spa.framework.compose
+
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.text.KeyboardActionScope
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
+
+/**
+ * An action when run, hides the keyboard if it's open.
+ */
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun hideKeyboardAction(): KeyboardActionScope.() -> Unit {
+ val keyboardController = LocalSoftwareKeyboardController.current
+ return { keyboardController?.hide() }
+}
+
+/**
+ * Creates a [LazyListState] that is remembered across compositions.
+ *
+ * And when user scrolling the lazy list, hides the keyboard if it's open.
+ */
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun rememberLazyListStateAndHideKeyboardWhenStartScroll(): LazyListState {
+ val listState = rememberLazyListState()
+ val keyboardController = LocalSoftwareKeyboardController.current
+ LaunchedEffect(listState) {
+ snapshotFlow { listState.isScrollInProgress }
+ .distinctUntilChanged()
+ .filter { it }
+ .collect { keyboardController?.hide() }
+ }
+ return listState
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OverridableFlow.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OverridableFlow.kt
new file mode 100644
index 0000000..1b33dd6
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OverridableFlow.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.settingslib.spa.framework.compose
+
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.receiveAsFlow
+
+/**
+ * A flow which result is overridable.
+ */
+class OverridableFlow<T>(flow: Flow<T>) {
+ private val overrideChannel = Channel<T>()
+
+ val flow = merge(overrideChannel.receiveAsFlow(), flow)
+
+ fun override(value: T) {
+ overrideChannel.trySend(value)
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
index bf33857..4df7794 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
@@ -40,7 +40,6 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filter
@@ -214,6 +213,7 @@
horizontalAlignment = horizontalAlignment,
reverseLayout = reverseLayout,
contentPadding = contentPadding,
+ userScrollEnabled = false,
modifier = modifier,
) {
items(
@@ -241,6 +241,7 @@
horizontalArrangement = Arrangement.spacedBy(itemSpacing, horizontalAlignment),
reverseLayout = reverseLayout,
contentPadding = contentPadding,
+ userScrollEnabled = false,
modifier = modifier,
) {
items(
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt
index 3015080..9eaa88a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt
@@ -120,12 +120,11 @@
val allPageWithEntry = remember { entryRepository.getAllPageWithEntry() }
RegularScaffold(title = "All Pages (${allPageWithEntry.size})") {
for (pageWithEntry in allPageWithEntry) {
+ val page = pageWithEntry.page
Preference(object : PreferenceModel {
- override val title =
- "${pageWithEntry.page.displayName} (${pageWithEntry.entries.size})"
- override val summary = pageWithEntry.page.formatArguments().toState()
- override val onClick =
- navigator(route = ROUTE_PAGE + "/${pageWithEntry.page.id}")
+ override val title = "${page.debugBrief()} (${pageWithEntry.entries.size})"
+ override val summary = page.debugArguments().toState()
+ override val onClick = navigator(route = ROUTE_PAGE + "/${page.id}")
})
}
}
@@ -146,16 +145,16 @@
val entryRepository by spaEnvironment.entryRepository
val id = arguments!!.getString(PARAM_NAME_PAGE_ID, "")
val pageWithEntry = entryRepository.getPageWithEntry(id)!!
- RegularScaffold(title = "Page - ${pageWithEntry.page.displayName}") {
- Text(text = "id = ${pageWithEntry.page.id}")
- Text(text = pageWithEntry.page.formatArguments())
+ val page = pageWithEntry.page
+ RegularScaffold(title = "Page - ${page.debugBrief()}") {
+ Text(text = "id = ${page.id}")
+ Text(text = page.debugArguments())
Text(text = "Entry size: ${pageWithEntry.entries.size}")
Preference(model = object : PreferenceModel {
override val title = "open page"
override val enabled =
- pageWithEntry.page.isBrowsable(context, spaEnvironment.browseActivityClass)
- .toState()
- override val onClick = openPage(pageWithEntry.page)
+ page.isBrowsable(context, spaEnvironment.browseActivityClass).toState()
+ override val onClick = openPage(page)
})
EntryList(pageWithEntry.entries)
}
@@ -167,8 +166,8 @@
val entryRepository by spaEnvironment.entryRepository
val id = arguments!!.getString(PARAM_NAME_ENTRY_ID, "")
val entry = entryRepository.getEntry(id)!!
- val entryContent = remember { entry.formatContent() }
- RegularScaffold(title = "Entry - ${entry.displayTitle()}") {
+ val entryContent = remember { entry.debugContent(entryRepository) }
+ RegularScaffold(title = "Entry - ${entry.debugBrief()}") {
Preference(model = object : PreferenceModel {
override val title = "open entry"
override val enabled =
@@ -184,7 +183,7 @@
private fun EntryList(entries: Collection<SettingsEntry>) {
for (entry in entries) {
Preference(object : PreferenceModel {
- override val title = entry.displayTitle()
+ override val title = entry.debugBrief()
override val summary =
"${entry.fromPage?.displayName} -> ${entry.toPage?.displayName}".toState()
override val onClick = navigator(route = ROUTE_ENTRY + "/${entry.id}")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugFormat.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugFormat.kt
new file mode 100644
index 0000000..538d2b5
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugFormat.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.settingslib.spa.framework.debug
+
+import com.android.settingslib.spa.framework.common.EntrySearchData
+import com.android.settingslib.spa.framework.common.EntryStatusData
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryRepository
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.util.normalize
+
+private fun EntrySearchData.debugContent(): String {
+ val content = listOf(
+ "search_title = $title",
+ "search_keyword = $keyword",
+ )
+ return content.joinToString("\n")
+}
+
+private fun EntryStatusData.debugContent(): String {
+ val content = listOf(
+ "is_disabled = $isDisabled",
+ "is_switch_off = $isSwitchOff",
+ )
+ return content.joinToString("\n")
+}
+
+fun SettingsPage.debugArguments(): String {
+ val normArguments = parameter.normalize(arguments)
+ if (normArguments == null || normArguments.isEmpty) return "[No arguments]"
+ return normArguments.toString().removeRange(0, 6)
+}
+
+fun SettingsPage.debugBrief(): String {
+ return displayName
+}
+
+fun SettingsEntry.debugBrief(): String {
+ return "${owner.displayName}:$displayName"
+}
+
+fun SettingsEntry.debugContent(entryRepository: SettingsEntryRepository): String {
+ val searchData = getSearchData()
+ val statusData = getStatusData()
+ val entryPathWithName = entryRepository.getEntryPathWithDisplayName(id)
+ val entryPathWithTitle = entryRepository.getEntryPathWithTitle(id,
+ searchData?.title ?: displayName)
+ val content = listOf(
+ "------ STATIC ------",
+ "id = $id",
+ "owner = ${owner.debugBrief()} ${owner.debugArguments()}",
+ "linkFrom = ${fromPage?.debugBrief()} ${fromPage?.debugArguments()}",
+ "linkTo = ${toPage?.debugBrief()} ${toPage?.debugArguments()}",
+ "hierarchy_path = $entryPathWithName",
+ "------ SEARCH ------",
+ "search_path = $entryPathWithTitle",
+ searchData?.debugContent() ?: "no search data",
+ statusData?.debugContent() ?: "no status data",
+ )
+ return content.joinToString("\n")
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt
index 6c27109..399278d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugProvider.kt
@@ -151,9 +151,9 @@
.add(ColumnEnum.PAGE_ID.id, page.id)
.add(ColumnEnum.PAGE_NAME.id, page.displayName)
.add(ColumnEnum.PAGE_ROUTE.id, page.buildRoute())
+ .add(ColumnEnum.PAGE_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
.add(ColumnEnum.PAGE_ENTRY_COUNT.id, pageWithEntry.entries.size)
.add(ColumnEnum.HAS_RUNTIME_PARAM.id, if (page.hasRuntimeParam()) 1 else 0)
- .add(ColumnEnum.PAGE_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
}
return cursor
}
@@ -170,6 +170,8 @@
.add(ColumnEnum.ENTRY_NAME.id, entry.displayName)
.add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute())
.add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
+ .add(ColumnEnum.ENTRY_HIERARCHY_PATH.id,
+ entryRepository.getEntryPathWithDisplayName(entry.id))
}
return cursor
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsFontFamily.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsFontFamily.kt
new file mode 100644
index 0000000..8e8805a
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsFontFamily.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package com.android.settingslib.spa.framework.theme
+
+import android.annotation.SuppressLint
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalInspectionMode
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.font.DeviceFontFamilyName
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+
+internal data class SettingsFontFamily(
+ val brand: FontFamily = FontFamily.Default,
+ val plain: FontFamily = FontFamily.Default,
+)
+
+private fun Context.getSettingsFontFamily(inInspection: Boolean): SettingsFontFamily {
+ if (inInspection) {
+ return SettingsFontFamily()
+ }
+ return SettingsFontFamily(
+ brand = FontFamily(
+ Font(getFontFamilyName("config_headlineFontFamily"), FontWeight.Normal),
+ Font(getFontFamilyName("config_headlineFontFamilyMedium"), FontWeight.Medium),
+ ),
+ plain = FontFamily(
+ Font(getFontFamilyName("config_bodyFontFamily"), FontWeight.Normal),
+ Font(getFontFamilyName("config_bodyFontFamilyMedium"), FontWeight.Medium),
+ ),
+ )
+}
+
+private fun Context.getFontFamilyName(configName: String): DeviceFontFamilyName {
+ @SuppressLint("DiscouragedApi")
+ val configId = resources.getIdentifier(configName, "string", "android")
+ return DeviceFontFamilyName(resources.getString(configId))
+}
+
+@Composable
+internal fun rememberSettingsFontFamily(): SettingsFontFamily {
+ val context = LocalContext.current
+ val inInspection = LocalInspectionMode.current
+ return remember { context.getSettingsFontFamily(inInspection) }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt
index 69ddf01..c8faef6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt
@@ -21,4 +21,5 @@
const val Disabled = 0.38f
const val Divider = 0.2f
const val SurfaceTone = 0.14f
+ const val Hint = 0.9f
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt
index 07f09ba..03699bf 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt
@@ -20,14 +20,13 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
-private class SettingsTypography {
- private val brand = FontFamily.Default
- private val plain = FontFamily.Default
+private class SettingsTypography(settingsFontFamily: SettingsFontFamily) {
+ private val brand = settingsFontFamily.brand
+ private val plain = settingsFontFamily.plain
val typography = Typography(
displayLarge = TextStyle(
@@ -140,5 +139,6 @@
@Composable
internal fun rememberSettingsTypography(): Typography {
- return remember { SettingsTypography().typography }
+ val settingsFontFamily = rememberSettingsFontFamily()
+ return remember { SettingsTypography(settingsFontFamily).typography }
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
index 6ebe6bb..895edf7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.graphics.vector.ImageVector
import com.android.settingslib.spa.framework.common.EntryMacro
import com.android.settingslib.spa.framework.common.EntrySearchData
+import com.android.settingslib.spa.framework.common.EntryStatusData
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.framework.util.wrapOnClickWithLog
@@ -55,6 +56,10 @@
keyword = searchKeywords
)
}
+
+ override fun getStatusData(): EntryStatusData {
+ return EntryStatusData(isDisabled = false)
+ }
}
/**
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
index 6a88f2d..764973f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
@@ -16,9 +16,12 @@
package com.android.settingslib.spa.widget.scaffold
+import androidx.appcompat.R
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack
+import androidx.compose.material.icons.outlined.Clear
+import androidx.compose.material.icons.outlined.FindInPage
import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.Icon
@@ -31,17 +34,23 @@
import androidx.compose.ui.res.stringResource
import com.android.settingslib.spa.framework.compose.LocalNavController
+/** Action that navigates back to last page. */
@Composable
internal fun NavigateBack() {
val navController = LocalNavController.current
- val contentDescription = stringResource(
- id = androidx.appcompat.R.string.abc_action_bar_up_description,
- )
+ val contentDescription = stringResource(R.string.abc_action_bar_up_description)
BackAction(contentDescription) {
navController.navigateBack()
}
}
+/** Action that collapses the search bar. */
+@Composable
+internal fun CollapseAction(onClick: () -> Unit) {
+ val contentDescription = stringResource(R.string.abc_toolbar_collapse_description)
+ BackAction(contentDescription, onClick)
+}
+
@Composable
private fun BackAction(contentDescription: String, onClick: () -> Unit) {
IconButton(onClick) {
@@ -52,6 +61,28 @@
}
}
+/** Action that expends the search bar. */
+@Composable
+internal fun SearchAction(onClick: () -> Unit) {
+ IconButton(onClick) {
+ Icon(
+ imageVector = Icons.Outlined.FindInPage,
+ contentDescription = stringResource(R.string.search_menu_title),
+ )
+ }
+}
+
+/** Action that clear the search query. */
+@Composable
+internal fun ClearAction(onClick: () -> Unit) {
+ IconButton(onClick) {
+ Icon(
+ imageVector = Icons.Outlined.Clear,
+ contentDescription = stringResource(R.string.abc_searchview_description_clear),
+ )
+ }
+}
+
@Composable
fun MoreOptionsAction(
content: @Composable ColumnScope.(onDismissRequest: () -> Unit) -> Unit,
@@ -71,9 +102,7 @@
IconButton(onClick) {
Icon(
imageVector = Icons.Outlined.MoreVert,
- contentDescription = stringResource(
- id = androidx.appcompat.R.string.abc_action_menu_overflow_description,
- )
+ contentDescription = stringResource(R.string.abc_action_menu_overflow_description),
)
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
new file mode 100644
index 0000000..4f83ad6
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalMaterial3Api::class)
+
+package com.android.settingslib.spa.widget.scaffold
+
+import androidx.activity.compose.BackHandler
+import androidx.appcompat.R
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.android.settingslib.spa.framework.compose.hideKeyboardAction
+import com.android.settingslib.spa.framework.theme.SettingsOpacity
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+
+/**
+ * A [Scaffold] which content is can be full screen, and with a search feature built-in.
+ */
+@Composable
+fun SearchScaffold(
+ title: String,
+ actions: @Composable RowScope.() -> Unit = {},
+ content: @Composable (searchQuery: State<String>) -> Unit,
+) {
+ val viewModel: SearchScaffoldViewModel = viewModel()
+
+ Scaffold(
+ topBar = {
+ SearchableTopAppBar(
+ title = title,
+ actions = actions,
+ searchQuery = viewModel.searchQuery,
+ ) { viewModel.searchQuery = it }
+ },
+ ) { paddingValues ->
+ Box(
+ Modifier
+ .padding(paddingValues)
+ .fillMaxSize()
+ ) {
+ val searchQuery = remember {
+ derivedStateOf { viewModel.searchQuery?.text ?: "" }
+ }
+ content(searchQuery)
+ }
+ }
+}
+
+internal class SearchScaffoldViewModel : ViewModel() {
+ var searchQuery: TextFieldValue? by mutableStateOf(null)
+}
+
+@Composable
+private fun SearchableTopAppBar(
+ title: String,
+ actions: @Composable RowScope.() -> Unit,
+ searchQuery: TextFieldValue?,
+ onSearchQueryChange: (TextFieldValue?) -> Unit,
+) {
+ if (searchQuery != null) {
+ SearchTopAppBar(
+ query = searchQuery,
+ onQueryChange = onSearchQueryChange,
+ onClose = { onSearchQueryChange(null) },
+ actions = actions,
+ )
+ } else {
+ SettingsTopAppBar(title) {
+ SearchAction { onSearchQueryChange(TextFieldValue()) }
+ actions()
+ }
+ }
+}
+
+@Composable
+private fun SearchTopAppBar(
+ query: TextFieldValue,
+ onQueryChange: (TextFieldValue) -> Unit,
+ onClose: () -> Unit,
+ actions: @Composable RowScope.() -> Unit = {},
+) {
+ TopAppBar(
+ title = { SearchBox(query, onQueryChange) },
+ modifier = Modifier.statusBarsPadding(),
+ navigationIcon = { CollapseAction(onClose) },
+ actions = {
+ if (query.text.isNotEmpty()) {
+ ClearAction { onQueryChange(TextFieldValue()) }
+ }
+ actions()
+ },
+ colors = settingsTopAppBarColors(),
+ )
+ BackHandler { onClose() }
+}
+
+@Composable
+private fun SearchBox(query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit) {
+ val focusRequester = remember { FocusRequester() }
+ val textStyle = MaterialTheme.typography.bodyLarge
+ TextField(
+ value = query,
+ onValueChange = onQueryChange,
+ modifier = Modifier
+ .fillMaxWidth()
+ .focusRequester(focusRequester),
+ textStyle = textStyle,
+ placeholder = {
+ Text(
+ text = stringResource(R.string.abc_search_hint),
+ modifier = Modifier.alpha(SettingsOpacity.Hint),
+ style = textStyle,
+ )
+ },
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
+ keyboardActions = KeyboardActions(onSearch = hideKeyboardAction()),
+ singleLine = true,
+ colors = TextFieldDefaults.textFieldColors(
+ containerColor = Color.Transparent,
+ focusedIndicatorColor = Color.Transparent,
+ unfocusedIndicatorColor = Color.Transparent,
+ ),
+ )
+
+ LaunchedEffect(focusRequester) {
+ focusRequester.requestFocus()
+ }
+}
+
+@Preview
+@Composable
+private fun SearchTopAppBarPreview() {
+ SettingsTheme {
+ SearchTopAppBar(query = TextFieldValue(), onQueryChange = {}, onClose = {}) {}
+ }
+}
+
+@Preview
+@Composable
+private fun SearchScaffoldPreview() {
+ SettingsTheme {
+ SearchScaffold(title = "App notifications") {}
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
index d17e464..3bc3dd7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
@@ -18,17 +18,10 @@
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
-import androidx.compose.material3.SmallTopAppBar
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
-import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme
/**
@@ -42,32 +35,11 @@
content: @Composable (PaddingValues) -> Unit,
) {
Scaffold(
- topBar = {
- SmallTopAppBar(
- title = {
- Text(
- text = title,
- modifier = Modifier.padding(SettingsDimension.itemPaddingAround),
- overflow = TextOverflow.Ellipsis,
- maxLines = 1,
- )
- },
- navigationIcon = { NavigateBack() },
- actions = actions,
- colors = settingsTopAppBarColors(),
- )
- },
+ topBar = { SettingsTopAppBar(title, actions) },
content = content,
)
}
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-internal fun settingsTopAppBarColors() = TopAppBarDefaults.largeTopAppBarColors(
- containerColor = SettingsTheme.colorScheme.surfaceHeader,
- scrolledContainerColor = SettingsTheme.colorScheme.surfaceHeader,
-)
-
@Preview
@Composable
private fun SettingsScaffoldPreview() {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt
new file mode 100644
index 0000000..9353520
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.settingslib.spa.widget.scaffold
+
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextOverflow
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun SettingsTopAppBar(
+ title: String,
+ actions: @Composable RowScope.() -> Unit,
+) {
+ TopAppBar(
+ title = {
+ Text(
+ text = title,
+ modifier = Modifier.padding(SettingsDimension.itemPaddingAround),
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ )
+ },
+ navigationIcon = { NavigateBack() },
+ actions = actions,
+ colors = settingsTopAppBarColors(),
+ )
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun settingsTopAppBarColors() = TopAppBarDefaults.smallTopAppBarColors(
+ containerColor = SettingsTheme.colorScheme.surfaceHeader,
+ scrolledContainerColor = SettingsTheme.colorScheme.surfaceHeader,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt
index b969076..9831b91 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt
@@ -16,30 +16,26 @@
package com.android.settingslib.spa.widget.ui
-import androidx.compose.material3.Checkbox
-import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import com.android.settingslib.spa.framework.util.wrapOnSwitchWithLog
-@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsSwitch(
checked: State<Boolean?>,
changeable: State<Boolean>,
onCheckedChange: ((newChecked: Boolean) -> Unit)? = null,
) {
- // TODO: Replace Checkbox with Switch when the androidx.compose.material3_material3 library is
- // updated to date.
val checkedValue = checked.value
if (checkedValue != null) {
- Checkbox(
+ Switch(
checked = checkedValue,
onCheckedChange = wrapOnSwitchWithLog(onCheckedChange),
enabled = changeable.value,
)
} else {
- Checkbox(
+ Switch(
checked = false,
onCheckedChange = null,
enabled = false,
diff --git a/packages/SettingsLib/Spa/tests/build.gradle b/packages/SettingsLib/Spa/tests/build.gradle
index b43bf18..4b4c6a3 100644
--- a/packages/SettingsLib/Spa/tests/build.gradle
+++ b/packages/SettingsLib/Spa/tests/build.gradle
@@ -55,11 +55,6 @@
composeOptions {
kotlinCompilerExtensionVersion jetpack_compose_compiler_version
}
- packagingOptions {
- resources {
- excludes += '/META-INF/{AL2.0,LGPL2.1}'
- }
- }
}
dependencies {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/OverridableFlowTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/OverridableFlowTest.kt
new file mode 100644
index 0000000..c94572b
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/OverridableFlowTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.settingslib.spa.framework.compose
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.withTimeout
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class OverridableFlowTest {
+
+ @Test
+ fun noOverride() = runTest {
+ val overridableFlow = OverridableFlow(flowOf(true))
+
+ launch {
+ val values = collectValues(overridableFlow.flow)
+ assertThat(values).containsExactly(true)
+ }
+ }
+
+ @Test
+ fun whenOverride() = runTest {
+ val overridableFlow = OverridableFlow(flowOf(true))
+
+ overridableFlow.override(false)
+
+ launch {
+ val values = collectValues(overridableFlow.flow)
+ assertThat(values).containsExactly(true, false).inOrder()
+ }
+ }
+
+ private suspend fun <T> collectValues(flow: Flow<T>): List<T> = withTimeout(500) {
+ val flowValues = mutableListOf<T>()
+ flow.toList(flowValues)
+ flowValues
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
new file mode 100644
index 0000000..ec3379d
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.settingslib.spa.widget.scaffold
+
+import android.content.Context
+import androidx.appcompat.R
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.State
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performTextInput
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SearchScaffoldTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Test
+ fun initialState_titleIsDisplayed() {
+ composeTestRule.setContent {
+ SearchScaffold(title = TITLE) {}
+ }
+
+ composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+ }
+
+ @Test
+ fun initialState_clearButtonNotExist() {
+ setContent()
+
+ onClearButton().assertDoesNotExist()
+ }
+
+ @Test
+ fun initialState_searchQueryIsEmpty() {
+ val searchQuery = setContent()
+
+ assertThat(searchQuery.value).isEqualTo("")
+ }
+
+ @Test
+ fun canEnterSearchMode() {
+ val searchQuery = setContent()
+
+ clickSearchButton()
+
+ composeTestRule.onNodeWithText(TITLE).assertDoesNotExist()
+ onSearchHint().assertIsDisplayed()
+ onClearButton().assertDoesNotExist()
+ assertThat(searchQuery.value).isEqualTo("")
+ }
+
+ @Test
+ fun canExitSearchMode() {
+ val searchQuery = setContent()
+
+ clickSearchButton()
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(R.string.abc_toolbar_collapse_description)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+ onSearchHint().assertDoesNotExist()
+ onClearButton().assertDoesNotExist()
+ assertThat(searchQuery.value).isEqualTo("")
+ }
+
+ @Test
+ fun canEnterSearchQuery() {
+ val searchQuery = setContent()
+
+ clickSearchButton()
+ onSearchHint().performTextInput(QUERY)
+
+ onClearButton().assertIsDisplayed()
+ assertThat(searchQuery.value).isEqualTo(QUERY)
+ }
+
+ @Test
+ fun canClearSearchQuery() {
+ val searchQuery = setContent()
+
+ clickSearchButton()
+ onSearchHint().performTextInput(QUERY)
+ onClearButton().performClick()
+
+ onClearButton().assertDoesNotExist()
+ assertThat(searchQuery.value).isEqualTo("")
+ }
+
+ private fun setContent(): State<String> {
+ lateinit var actualSearchQuery: State<String>
+ composeTestRule.setContent {
+ SearchScaffold(title = TITLE) { searchQuery ->
+ SideEffect {
+ actualSearchQuery = searchQuery
+ }
+ }
+ }
+ return actualSearchQuery
+ }
+
+ private fun clickSearchButton() {
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(R.string.search_menu_title)
+ ).performClick()
+ }
+
+ private fun onSearchHint() = composeTestRule.onNodeWithText(
+ context.getString(R.string.abc_search_hint)
+ )
+
+ private fun onClearButton() = composeTestRule.onNodeWithContentDescription(
+ context.getString(R.string.abc_searchview_description_clear)
+ )
+
+ private companion object {
+ const val TITLE = "title"
+ const val QUERY = "query"
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
index 9964926..fd723dd 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
@@ -1,24 +1,57 @@
+/*
+ * 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.settingslib.spaprivileged.framework.common
+import android.app.AlarmManager
+import android.app.AppOpsManager
import android.app.admin.DevicePolicyManager
import android.app.usage.StorageStatsManager
+import android.apphibernation.AppHibernationManager
import android.content.Context
import android.content.pm.verify.domain.DomainVerificationManager
import android.os.UserHandle
import android.os.UserManager
+import android.permission.PermissionControllerManager
-/** The [UserManager] instance. */
-val Context.userManager get() = getSystemService(UserManager::class.java)!!
+/** The [AlarmManager] instance. */
+val Context.alarmManager get() = getSystemService(AlarmManager::class.java)!!
+
+/** The [AppHibernationManager] instance. */
+val Context.appHibernationManager get() = getSystemService(AppHibernationManager::class.java)!!
+
+/** The [AppOpsManager] instance. */
+val Context.appOpsManager get() = getSystemService(AppOpsManager::class.java)!!
/** The [DevicePolicyManager] instance. */
val Context.devicePolicyManager get() = getSystemService(DevicePolicyManager::class.java)!!
-/** The [StorageStatsManager] instance. */
-val Context.storageStatsManager get() = getSystemService(StorageStatsManager::class.java)!!
-
/** The [DomainVerificationManager] instance. */
val Context.domainVerificationManager
get() = getSystemService(DomainVerificationManager::class.java)!!
+/** The [PermissionControllerManager] instance. */
+val Context.permissionControllerManager
+ get() = getSystemService(PermissionControllerManager::class.java)!!
+
+/** The [StorageStatsManager] instance. */
+val Context.storageStatsManager get() = getSystemService(StorageStatsManager::class.java)!!
+
+/** The [UserManager] instance. */
+val Context.userManager get() = getSystemService(UserManager::class.java)!!
+
/** Gets a new [Context] for the given [UserHandle]. */
fun Context.asUser(userHandle: UserHandle): Context = createContextAsUser(userHandle, 0)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index c5ad181..408b9df 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -19,7 +19,6 @@
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
@@ -29,6 +28,7 @@
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.settingslib.spa.framework.compose.LogCompositions
import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
+import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
import com.android.settingslib.spa.framework.compose.toState
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.ui.PlaceholderTitle
@@ -76,7 +76,7 @@
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
- state = rememberLazyListState(),
+ state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
contentPadding = PaddingValues(bottom = SettingsDimension.itemPaddingVertical),
) {
items(count = list.size, key = { option to list[it].record.app.packageName }) {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index 2be1d1c..99376b0 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -17,9 +17,7 @@
package com.android.settingslib.spaprivileged.template.app
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -28,9 +26,8 @@
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.scaffold.MoreOptionsAction
-import com.android.settingslib.spa.widget.scaffold.SettingsScaffold
+import com.android.settingslib.spa.widget.scaffold.SearchScaffold
import com.android.settingslib.spa.widget.ui.Spinner
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppListConfig
@@ -50,14 +47,12 @@
appItem: @Composable (itemState: AppListItemModel<T>) -> Unit,
) {
val showSystem = rememberSaveable { mutableStateOf(false) }
- // TODO: Use SearchScaffold here.
- SettingsScaffold(
+ SearchScaffold(
title = title,
actions = {
ShowSystemAction(showSystem.value) { showSystem.value = it }
},
- ) { paddingValues ->
- Spacer(Modifier.padding(paddingValues))
+ ) { searchQuery ->
WorkProfilePager(primaryUserOnly) { userInfo ->
Column(Modifier.fillMaxSize()) {
val options = remember { listModel.getSpinnerOptions() }
@@ -71,7 +66,7 @@
listModel = listModel,
showSystem = showSystem,
option = selectedOption,
- searchQuery = stateOf(""),
+ searchQuery = searchQuery,
appItem = appItem,
)
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 808ea9e..6d375ac 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -549,7 +549,7 @@
try {
IActivityManager am = ActivityManager.getService();
- Configuration config = am.getConfiguration();
+ final Configuration config = new Configuration();
config.setLocales(merged);
// indicate this isn't some passing default - the user wants this remembered
config.userSetLocale = true;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 765ee89..c388826 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -42,8 +42,6 @@
import android.util.Base64;
import android.util.Slog;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -51,6 +49,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
@@ -1087,6 +1087,7 @@
parseStateLocked(parser);
return true;
} catch (XmlPullParserException | IOException e) {
+ Slog.e(LOG_TAG, "parse settings xml failed", e);
return false;
} finally {
IoUtils.closeQuietly(in);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 4ed28d5..55160fb 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -17,9 +17,10 @@
import android.os.Looper;
import android.test.AndroidTestCase;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlSerializer;
+
import com.google.common.base.Strings;
import java.io.ByteArrayOutputStream;
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index d5e84f9..d5552f6 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon word vereis nadat toestel herbegin het"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN word vereis nadat toestel herbegin het"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wagwoord word vereis nadat toestel herbegin het"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Patroon word vir bykomende sekuriteit vereis"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN word vir bykomende sekuriteit vereis"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Wagwoord word vir bykomende sekuriteit vereis"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Toestel is deur administrateur gesluit"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Toestel is handmatig gesluit"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie herken nie"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Verstek"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Borrel"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index be52c44..533e5a2 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"መሣሪያ ዳግም ከጀመረ በኋላ ሥርዓተ ጥለት ያስፈልጋል"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"መሣሪያ ዳግም ከተነሳ በኋላ ፒን ያስፈልጋል"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"መሣሪያ ዳግም ከጀመረ በኋላ የይለፍ ቃል ያስፈልጋል"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ሥርዓተ ጥለት ለተጨማሪ ደህንነት ያስፈልጋል"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ፒን ለተጨማሪ ደህንነት ያስፈልጋል"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"የይለፍ ቃል ለተጨማሪ ደህንነት ያስፈልጋል"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"መሣሪያ በአስተዳዳሪ ተቆልፏል"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"መሣሪያ በተጠቃሚው ራሱ ተቆልፏል"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"አልታወቀም"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ነባሪ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"አረፋ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"አናሎግ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index adb57b6..81ce7d3 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"يجب رسم النقش بعد إعادة تشغيل الجهاز"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"يجب إدخال كلمة المرور بعد إعادة تشغيل الجهاز"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"يجب رسم النقش لمزيد من الأمان"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"يجب إدخال رقم التعريف الشخصي لمزيد من الأمان"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"يجب إدخال كلمة المرور لمزيد من الأمان"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"اختار المشرف قفل الجهاز"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"تم حظر الجهاز يدويًا"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"لم يتم التعرّف عليه."</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"تلقائي"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"فقاعة"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ساعة تقليدية"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index cbfb325..443f666 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত আৰ্হি দিয়াটো বাধ্যতামূলক"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পিন দিয়াটো বাধ্যতামূলক"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পাছৱৰ্ড দিয়াটো বাধ্যতামূলক"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"অতিৰিক্ত সুৰক্ষাৰ বাবে আর্হি দিয়াটো বাধ্যতামূলক"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"অতিৰিক্ত সুৰক্ষাৰ বাবে পিন দিয়াটো বাধ্যতামূলক"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"অতিৰিক্ত সুৰক্ষাৰ বাবে পাছৱর্ড দিয়াটো বাধ্যতামূলক"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"প্ৰশাসকে ডিভাইচ লক কৰি ৰাখিছে"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ডিভাইচটো মেনুৱেলভাৱে লক কৰা হৈছিল"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"চিনাক্ত কৰিব পৰা নাই"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ডিফ’ল্ট"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"বাবল"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"এনাল’গ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 6ec1061..e125697 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cihaz yenidən başladıqdan sonra model tələb olunur"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cihaz yeniden başladıqdan sonra PIN tələb olunur"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cihaz yeniden başladıqdan sonra parol tələb olunur"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Əlavə təhlükəsizlik üçün model tələb olunur"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Əlavə təhlükəsizlik üçün PIN tələb olunur"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Əlavə təhlükəsizlik üçün parol tələb olunur"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz admin tərəfindən kilidlənib"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihaz əl ilə kilidləndi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmır"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Defolt"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Qabarcıq"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoq"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 13d6613..f0d1ef2 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Treba da unesete šablon kada se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Treba da unesete PIN kada se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Treba da unesete lozinku kada se uređaj ponovo pokrene"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Treba da unesete šablon radi dodatne bezbednosti"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Treba da unesete PIN radi dodatne bezbednosti"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Treba da unesete lozinku radi dodatne bezbednosti"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zaključao uređaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznat"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Podrazumevani"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mehurići"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogni"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 616d31a..e1af3ece 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Пасля перазапуску прылады патрабуецца ўзор"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Пасля перазапуску прылады патрабуецца PIN-код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Пасля перазапуску прылады патрабуецца пароль"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Для забеспячэння дадатковай бяспекі патрабуецца ўзор"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Для забеспячэння дадатковай бяспекі патрабуецца PIN-код"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Для забеспячэння дадатковай бяспекі патрабуецца пароль"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Прылада заблакіравана адміністратарам"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Прылада была заблакіравана ўручную"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не распазнана"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Стандартны"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Бурбалкі"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Са стрэлкамі"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 366a7f4..0b4417a 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"След рестартиране на устройството се изисква фигура"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"След рестартиране на устройството се изисква ПИН код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"След рестартиране на устройството се изисква парола"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"За допълнителна сигурност се изисква фигура"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"За допълнителна сигурност се изисква ПИН код"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"За допълнителна сигурност се изисква парола"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Устройството е заключено от администратора"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Устройството бе заключено ръчно"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не е разпознато"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Стандартен"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Балонен"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналогов"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index c20be5d..4851579 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ডিভাইসটি পুনরায় চালু হওয়ার পর প্যাটার্নের প্রয়োজন হবে"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ডিভাইসটি পুনরায় চালু হওয়ার পর পিন প্রয়োজন হবে"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ডিভাইসটি পুনরায় চালু হওয়ার পর পাসওয়ার্ডের প্রয়োজন হবে"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"অতিরিক্ত সুরক্ষার জন্য প্যাটার্ন দেওয়া প্রয়োজন"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"অতিরিক্ত সুরক্ষার জন্য পিন দেওয়া প্রয়োজন"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"অতিরিক্ত সুরক্ষার জন্য পাসওয়ার্ড দেওয়া প্রয়োজন"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"প্রশাসক ডিভাইসটি লক করেছেন"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ডিভাইসটিকে ম্যানুয়ালি লক করা হয়েছে"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"শনাক্ত করা যায়নি"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ডিফল্ট"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"বাবল"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"অ্যানালগ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index f1c00a9..4705b4d9 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Potreban je uzorak nakon što se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Potreban je PIN nakon što se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Potrebna je lozinka nakon što se uređaj ponovo pokrene"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Uzorak je potreban radi dodatne sigurnosti"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN je potreban radi dodatne sigurnosti"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Lozinka je potrebna radi dodatne sigurnosti"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Uređaj je zaključao administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Zadano"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mjehurići"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogni"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 709407c..284eaeb 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cal introduir el patró quan es reinicia el dispositiu"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cal introduir el PIN quan es reinicia el dispositiu"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cal introduir la contrasenya quan es reinicia el dispositiu"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Cal introduir el patró per disposar de més seguretat"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Cal introduir el PIN per disposar de més seguretat"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Cal introduir la contrasenya per disposar de més seguretat"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'administrador ha bloquejat el dispositiu"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositiu s\'ha bloquejat manualment"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No s\'ha reconegut"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminada"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bombolla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analògica"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index a44658c..6b4f607 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po restartování zařízení je vyžadováno gesto"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po restartování zařízení je vyžadován kód PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po restartování zařízení je vyžadováno heslo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pro ještě lepší zabezpečení je vyžadováno gesto"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Pro ještě lepší zabezpečení je vyžadován kód PIN"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Pro ještě lepší zabezpečení je vyžadováno heslo"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zařízení je uzamknuto administrátorem"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zařízení bylo ručně uzamčeno"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznáno"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Výchozí"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bublina"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogové"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 331c355..85238df 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du skal angive et mønster, når du har genstartet enheden"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Der skal angives en pinkode efter genstart af enheden"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Der skal angives en adgangskode efter genstart af enheden"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Der kræves et mønster som ekstra beskyttelse"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Der kræves en pinkode som ekstra beskyttelse"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Der kræves en adgangskode som ekstra beskyttelse"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheden er blevet låst af administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheden blev låst manuelt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke genkendt"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Boble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index c19b357..18befed 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Nach dem Neustart des Geräts ist die Eingabe des Musters erforderlich"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Nach dem Neustart des Geräts ist die Eingabe der PIN erforderlich"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Nach dem Neustart des Geräts ist die Eingabe des Passworts erforderlich"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Zur Verbesserung der Sicherheit ist ein Muster erforderlich"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Zur Verbesserung der Sicherheit ist eine PIN erforderlich"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Zur Verbesserung der Sicherheit ist ein Passwort erforderlich"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Gerät vom Administrator gesperrt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Gerät manuell gesperrt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nicht erkannt"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 1d6ec82..65b84486 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Απαιτείται μοτίβο μετά από την επανεκκίνηση της συσκευής"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Απαιτείται PIN μετά από την επανεκκίνηση της συσκευής"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Απαιτείται κωδικός πρόσβασης μετά από την επανεκκίνηση της συσκευής"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Απαιτείται μοτίβο για πρόσθετη ασφάλεια"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Απαιτείται PIN για πρόσθετη ασφάλεια"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Απαιτείται κωδικός πρόσβασης για πρόσθετη ασφάλεια"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Η συσκευή κλειδώθηκε από τον διαχειριστή"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Η συσκευή κλειδώθηκε με μη αυτόματο τρόπο"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Δεν αναγνωρίστηκε"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Προεπιλογή"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Συννεφάκι"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Αναλογικό"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 2b78f96..588f1b5 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pattern required for additional security"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN required for additional security"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index e1c2532..08fc8d6 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pattern required for additional security"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN required for additional security"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 2b78f96..588f1b5 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pattern required for additional security"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN required for additional security"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 2b78f96..588f1b5 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pattern required for additional security"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN required for additional security"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index 9052e4f..a23aeb0 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pattern required for additional security"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN required for additional security"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password required for additional security"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognized"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Unlock your device to continue"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 9dc054a..c71a678 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Se requiere el patrón después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Se requiere el PIN después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Se requiere la contraseña después de reiniciar el dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Se requiere el patrón por razones de seguridad"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Se requiere el PIN por razones de seguridad"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Se requiere la contraseña por razones de seguridad"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se bloqueó de forma manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoció"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index f9f0452..c6ee698 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Debes introducir el patrón después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Debes introducir el PIN después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Debes introducir la contraseña después de reiniciar el dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Debes introducir el patrón como medida de seguridad adicional"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Debes introducir el PIN como medida de seguridad adicional"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Debes introducir la contraseña como medida de seguridad adicional"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se ha bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoce"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index dceb78e..071ede8 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pärast seadme taaskäivitamist tuleb sisestada muster"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pärast seadme taaskäivitamist tuleb sisestada PIN-kood"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pärast seadme taaskäivitamist tuleb sisestada parool"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Lisaturvalisuse huvides tuleb sisestada muster"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Lisaturvalisuse huvides tuleb sisestada PIN-kood"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Lisaturvalisuse huvides tuleb sisestada parool"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administraator lukustas seadme"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Seade lukustati käsitsi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tuvastatud"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Vaikenumbrilaud"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mull"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 8431268..9b8e65b 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Eredua marraztu beharko duzu gailua berrabiarazten denean"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PINa idatzi beharko duzu gailua berrabiarazten denean"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pasahitza idatzi beharko duzu gailua berrabiarazten denean"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Eredua behar da gailua babestuago izateko"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PINa behar da gailua babestuago izateko"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Pasahitza behar da gailua babestuago izateko"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratzaileak blokeatu egin du gailua"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Eskuz blokeatu da gailua"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ez da ezagutu"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Lehenetsia"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Puxikak"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogikoa"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 37bb260..3583f1e 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"بعد از بازنشانی دستگاه باید الگو وارد شود"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"بعد از بازنشانی دستگاه باید پین وارد شود"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"بعد از بازنشانی دستگاه باید گذرواژه وارد شود"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"برای ایمنی بیشتر باید الگو وارد شود"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"برای ایمنی بیشتر باید پین وارد شود"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"برای ایمنی بیشتر باید گذرواژه وارد شود"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"دستگاه توسط سرپرست سیستم قفل شده است"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"دستگاه بهصورت دستی قفل شده است"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"شناسایی نشد"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"پیشفرض"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"حباب"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"آنالوگ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index f8cec42..a0ac6df 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kuvio vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN-koodi vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Salasana vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Kuvio vaaditaan suojauksen parantamiseksi."</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN-koodi vaaditaan suojauksen parantamiseksi."</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Salasana vaaditaan suojauksen parantamiseksi."</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Järjestelmänvalvoja lukitsi laitteen."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Laite lukittiin manuaalisesti"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tunnistettu"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Oletus"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Kupla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoginen"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 077fe11..66fd7c0 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Le schéma est exigé après le redémarrage de l\'appareil"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Le NIP est exigé après le redémarrage de l\'appareil"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Le mot de passe est exigé après le redémarrage de l\'appareil"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Le schéma est exigé pour plus de sécurité"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Le NIP est exigé pour plus de sécurité"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Le mot de passe est exigé pour plus de sécurité"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pour plus de sécurité, utilisez plutôt un schéma"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pour plus de sécurité, utilisez plutôt un NIP"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pour plus de sécurité, utilisez plutôt un mot de passe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'appareil a été verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"L\'appareil a été verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Doigt non reconnu"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Déverrouiller votre appareil pour continuer"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 45dadc1..ec00ba3 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Veuillez dessiner le schéma après le redémarrage de l\'appareil"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Veuillez saisir le code après le redémarrage de l\'appareil"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Veuillez saisir le mot de passe après le redémarrage de l\'appareil"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Veuillez dessiner le schéma pour renforcer la sécurité"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Veuillez saisir le code pour renforcer la sécurité"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Veuillez saisir le mot de passe pour renforcer la sécurité"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Appareil verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Appareil verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non reconnu"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 4fbdd67..a3f8e86 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"É necesario o padrón despois do reinicio do dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"É necesario o PIN despois do reinicio do dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"É necesario o contrasinal despois do reinicio do dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"É necesario o padrón para obter seguranza adicional"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"É necesario o PIN para obter seguranza adicional"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"É necesario o contrasinal para obter seguranza adicional"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"O administrador bloqueou o dispositivo"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo bloqueouse manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non se recoñeceu"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbulla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analóxico"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 6caac8a..c97fe01 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પૅટર્ન જરૂરી છે"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પિન જરૂરી છે"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પાસવર્ડ જરૂરી છે"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"વધારાની સુરક્ષા માટે પૅટર્ન જરૂરી છે"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"વધારાની સુરક્ષા માટે પિન જરૂરી છે"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"વધારાની સુરક્ષા માટે પાસવર્ડ જરૂરી છે"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"વ્યવસ્થાપકે ઉપકરણ લૉક કરેલું છે"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ઉપકરણ મેન્યુઅલી લૉક કર્યું હતું"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ઓળખાયેલ નથી"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ડિફૉલ્ટ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"બબલ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"એનાલોગ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 627576e..1283004 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"डिवाइस फिर से चालू होने के बाद पैटर्न ज़रूरी है"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"डिवाइस फिर से चालू होने के बाद पिन ज़रूरी है"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"डिवाइस फिर से चालू होने के बाद पासवर्ड ज़रूरी है"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"अतिरिक्त सुरक्षा के लिए पैटर्न ज़रूरी है"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"अतिरिक्त सुरक्षा के लिए पिन ज़रूरी है"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"अतिरिक्त सुरक्षा के लिए पासवर्ड ज़रूरी है"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"व्यवस्थापक ने डिवाइस को लॉक किया है"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"डिवाइस को मैन्युअल रूप से लॉक किया गया था"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहचान नहीं हो पाई"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"डिफ़ॉल्ट"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"बबल"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"एनालॉग"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 8b1b504..7a14a80 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Nakon ponovnog pokretanja uređaja morate unijeti uzorak"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Nakon ponovnog pokretanja uređaja morate unijeti PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Nakon ponovnog pokretanja uređaja morate unijeti zaporku"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Unesite uzorak radi dodatne sigurnosti"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Unesite PIN radi dodatne sigurnosti"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Unesite zaporku radi dodatne sigurnosti"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zaključao uređaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Zadano"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mjehurić"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogni"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 6b75e72..a4fbf53 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Az eszköz újraindítását követően meg kell adni a mintát"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Az eszköz újraindítását követően meg kell adni a PIN-kódot"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Az eszköz újraindítását követően meg kell adni a jelszót"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"A nagyobb biztonság érdekében minta szükséges"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"A nagyobb biztonság érdekében PIN-kód szükséges"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"A nagyobb biztonság érdekében jelszó szükséges"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"A rendszergazda zárolta az eszközt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Az eszközt manuálisan lezárták"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nem ismerhető fel"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Alapértelmezett"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Buborék"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analóg"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 3412026..086eeb9 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել նախշը"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել PIN կոդը"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել գաղտնաբառը"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել նախշը"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել PIN կոդը"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել գաղտնաբառը"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Սարքը կողպված է ադմինիստրատորի կողմից"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Սարքը կողպվել է ձեռքով"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Չհաջողվեց ճանաչել"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Կանխադրված"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Պղպջակ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Անալոգային"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 1afb791..b43a032 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pola diperlukan setelah perangkat dimulai ulang"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah perangkat dimulai ulang"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Sandi diperlukan setelah perangkat dimulai ulang"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Pola diperlukan untuk keamanan tambahan"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN diperlukan untuk keamanan tambahan"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Sandi diperlukan untuk keamanan tambahan"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Perangkat dikunci oleh admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Perangkat dikunci secara manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balon"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 6abdc82..8bad961 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Mynsturs er krafist þegar tækið er endurræst"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN-númers er krafist þegar tækið er endurræst"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Aðgangsorðs er krafist þegar tækið er endurræst"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Mynsturs er krafist af öryggisástæðum"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN-númers er krafist af öryggisástæðum"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Aðgangsorðs er krafist af öryggisástæðum"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Kerfisstjóri læsti tæki"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Tækinu var læst handvirkt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Þekktist ekki"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Sjálfgefið"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Blaðra"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Með vísum"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 9fed5f7..186177ff 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Sequenza obbligatoria dopo il riavvio del dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN obbligatorio dopo il riavvio del dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password obbligatoria dopo il riavvio del dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Sequenza obbligatoria per maggiore sicurezza"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN obbligatorio per maggiore sicurezza"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Password obbligatoria per maggiore sicurezza"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloccato dall\'amministratore"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Il dispositivo è stato bloccato manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogico"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index b5b1c53..aab4206 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"יש להזין את קו ביטול הנעילה לאחר הפעלה מחדש של המכשיר"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"צריך להזין קוד אימות לאחר הפעלה מחדש של המכשיר"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"יש להזין סיסמה לאחר הפעלה מחדש של המכשיר"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"יש להזין את קו ביטול הנעילה כדי להגביר את רמת האבטחה"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"יש להזין קוד אימות כדי להגביר את רמת האבטחה"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"יש להזין סיסמה כדי להגביר את רמת האבטחה"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"כדי להגביר את רמת האבטחה, כדאי להשתמש בקו ביטול נעילה במקום זאת"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"כדי להגביר את רמת האבטחה, כדאי להשתמש בקוד אימות במקום זאת"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"כדי להגביר את רמת האבטחה, כדאי להשתמש בסיסמה במקום זאת"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"המנהל של המכשיר נהל אותו"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"המכשיר ננעל באופן ידני"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"לא זוהתה"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ברירת מחדל"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"בועה"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"אנלוגי"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"צריך לבטל את הנעילה של המכשיר כדי להמשיך"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index afe0159..1a4fb0b 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"デバイスの再起動後はパターンの入力が必要となります"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"デバイスの再起動後は PIN の入力が必要となります"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"デバイスの再起動後はパスワードの入力が必要となります"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"追加の確認のためパターンが必要です"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"追加の確認のため PIN が必要です"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"追加の確認のためパスワードが必要です"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"セキュリティを強化するには代わりにパターンを使用してください"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"セキュリティを強化するには代わりに PIN を使用してください"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"セキュリティを強化するには代わりにパスワードを使用してください"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"デバイスは管理者によりロックされています"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"デバイスは手動でロックされました"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"認識されませんでした"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"デフォルト"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"バブル"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"アナログ"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"続行するにはデバイスのロックを解除してください"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index b32caa7..123cc39 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა ნიმუშის დახატვა"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა PIN-კოდის შეყვანა"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა პაროლის შეყვანა"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"დამატებითი უსაფრთხოებისთვის საჭიროა ნიმუშის დახატვა"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"დამატებითი უსაფრთხოებისთვის საჭიროა PIN-კოდის შეყვანა"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"დამატებითი უსაფრთხოებისთვის საჭიროა პაროლის შეყვანა"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"მოწყობილობა ჩაკეტილია ადმინისტრატორის მიერ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"მოწყობილობა ხელით ჩაიკეტა"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"არ არის ამოცნობილი"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ნაგულისხმევი"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ბუშტი"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ანალოგური"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index d6d5bcd..8daca5c 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Құрылғы қайта іске қосылғаннан кейін, өрнекті енгізу қажет"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Құрылғы қайта іске қосылғаннан кейін, PIN кодын енгізу қажет"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Құрылғы қайта іске қосылғаннан кейін, құпия сөзді енгізу қажет"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Қауіпсіздікті күшейту үшін өрнекті енгізу қажет"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Қауіпсіздікті күшейту үшін PIN кодын енгізу қажет"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Қауіпсіздікті күшейту үшін құпия сөзді енгізу қажет"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Құрылғыны әкімші құлыптаған"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Құрылғы қолмен құлыпталды"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Танылмады"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Әдепкі"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Көпіршік"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналогтық"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 00bfe05..73f507c 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"តម្រូវឲ្យប្រើលំនាំ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"តម្រូវឲ្យប្រើលំនាំ ដើម្បីទទួលបានសវុត្ថិភាពបន្ថែម"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"តម្រូវឲ្យបញ្ចូលកូដ PIN ដើម្បីទទួលបានសុវត្ថិភាពបន្ថែម"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ ដើម្បីទទួលបានសុវត្ថិភាពបន្ថែម"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ឧបករណ៍ត្រូវបានចាក់សោដោយអ្នកគ្រប់គ្រង"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ឧបករណ៍ត្រូវបានចាក់សោដោយអ្នកប្រើផ្ទាល់"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"មិនអាចសម្គាល់បានទេ"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"លំនាំដើម"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ពពុះ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"អាណាឡូក"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 80a98e6..c279cea 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗೆ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿದೆ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗೆ ಪಿನ್ ಅಗತ್ಯವಿದೆ"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿದೆ"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ನಿರ್ವಾಹಕರು ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಿದ್ದಾರೆ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ಸಾಧನವನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ಡೀಫಾಲ್ಟ್"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ಬಬಲ್"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ಅನಲಾಗ್"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index b952f1b..4c058ed 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"기기가 다시 시작되면 패턴이 필요합니다."</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"기기가 다시 시작되면 PIN이 필요합니다."</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"기기가 다시 시작되면 비밀번호가 필요합니다."</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"보안 강화를 위해 패턴이 필요합니다."</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"보안 강화를 위해 PIN이 필요합니다."</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"보안 강화를 위해 비밀번호가 필요합니다."</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"관리자가 기기를 잠갔습니다."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"기기가 수동으로 잠금 설정되었습니다."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"인식할 수 없음"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"기본"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"버블"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"아날로그"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 485337d..7c7099e 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Түзмөк кайра күйгүзүлгөндөн кийин графикалык ачкычты тартуу талап кылынат"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Түзмөк кайра күйгүзүлгөндөн кийин PIN-кодду киргизүү талап кылынат"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Түзмөк кайра күйгүзүлгөндөн кийин сырсөздү киргизүү талап кылынат"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Коопсуздукту бекемдөө үчүн графикалык ачкыч талап кылынат"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Коопсуздукту бекемдөө үчүн PIN-код талап кылынат"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Коопсуздукту бекемдөө үчүн сырсөз талап кылынат"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Түзмөктү администратор кулпулап койгон"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Түзмөк кол менен кулпуланды"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Таанылган жок"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Демейки"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Көбүк"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналог"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 17584b5..5a6df42 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ຈຳເປັນຕ້ອງມີແບບຮູບປົດລັອກຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ຈຳເປັນຕ້ອງມີ PIN ຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ຈຳເປັນຕ້ອງມີແບບຮູບເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ຈຳເປັນຕ້ອງມີ PIN ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ອຸປະກອນຖືກລັອກໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ອຸປະກອນຖືກສັ່ງໃຫ້ລັອກ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ບໍ່ຮູ້ຈັກ"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ຄ່າເລີ່ມຕົ້ນ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ຟອງ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ໂມງເຂັມ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index a066a66..4d98fd1 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Iš naujo paleidus įrenginį būtinas atrakinimo piešinys"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Iš naujo paleidus įrenginį būtinas PIN kodas"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Iš naujo paleidus įrenginį būtinas slaptažodis"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Norint užtikrinti papildomą saugą būtinas atrakinimo piešinys"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Norint užtikrinti papildomą saugą būtinas PIN kodas"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Norint užtikrinti papildomą saugą būtinas slaptažodis"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Įrenginį užrakino administratorius"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Įrenginys užrakintas neautomatiškai"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Neatpažinta"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Numatytasis"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Debesėlis"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoginis"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index d371a4b..2660a06 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pēc ierīces restartēšanas ir jāievada atbloķēšanas kombinācija."</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pēc ierīces restartēšanas ir jāievada PIN kods."</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pēc ierīces restartēšanas ir jāievada parole."</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Papildu drošībai ir jāievada atbloķēšanas kombinācija."</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Papildu drošībai ir jāievada PIN kods."</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Papildu drošībai ir jāievada parole."</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrators bloķēja ierīci."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Ierīce tika bloķēta manuāli."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nav atpazīts"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Noklusējums"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuļi"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogais"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index ef22564..77e1b50 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Потребна е шема по рестартирање на уредот"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Потребен е PIN-код по рестартирање на уредот"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Потребна е лозинка по рестартирање на уредот"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Потребна е шема за дополнителна безбедност"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Потребен е PIN-код за дополнителна безбедност"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Потребна е лозинка за дополнителна безбедност"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"За дополнителна безбедност, користете шема"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"За дополнителна безбедност, користете PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"За дополнителна безбедност, користете лозинка"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Уредот е заклучен од администраторот"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Уредот е заклучен рачно"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Непознат"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Стандарден"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Балонче"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналоген"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Отклучете го уредот за да продолжите"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 63a542a..e62b435 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പാറ്റേൺ വരയ്ക്കേണ്ടതുണ്ട്"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പിൻ നൽകേണ്ടതുണ്ട്"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പാസ്വേഡ് നൽകേണ്ടതുണ്ട്"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"അധിക സുരക്ഷയ്ക്ക് പാറ്റേൺ ആവശ്യമാണ്"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"അധിക സുരക്ഷയ്ക്ക് പിൻ ആവശ്യമാണ്"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"അധിക സുരക്ഷയ്ക്ക് പാസ്വേഡ് ആവശ്യമാണ്"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ഉപകരണം അഡ്മിൻ ലോക്കുചെയ്തു"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ഉപകരണം നേരിട്ട് ലോക്കുചെയ്തു"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"തിരിച്ചറിയുന്നില്ല"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ഡിഫോൾട്ട്"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ബബിൾ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"അനലോഗ്"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 71c913f..f2cc5ab 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Төхөөрөмжийг дахин эхлүүлсний дараа загвар оруулах шаардлагатай"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Төхөөрөмжийг дахин эхлүүлсний дараа ПИН оруулах шаардлагатай"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Төхөөрөмжийг дахин эхлүүлсний дараа нууц үг оруулах шаардлагатай"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Аюулгүй байдлын үүднээс загвар оруулах шаардлагатай"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Аюулгүй байдлын үүднээс ПИН оруулах шаардлагатай"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Аюулгүй байдлын үүднээс нууц үг оруулах шаардлагатай"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Нэмэлт аюулгүй байдлын үүднээс оронд нь хээ ашиглана уу"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Нэмэлт аюулгүй байдлын үүднээс оронд нь ПИН ашиглана уу"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Нэмэлт аюулгүй байдлын үүднээс оронд нь нууц үг ашиглана уу"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Админ төхөөрөмжийг түгжсэн"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Төхөөрөмжийг гараар түгжсэн"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Таньж чадсангүй"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Өгөгдмөл"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Бөмбөлөг"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Aналог"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Үргэлжлүүлэхийн тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 6ac13bd..1454b20 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"डिव्हाइस रीस्टार्ट झाल्यावर पॅटर्न आवश्यक आहे"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"डिव्हाइस रीस्टार्ट झाल्यावर पिन आवश्यक आहे"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"डिव्हाइस रीस्टार्ट झाल्यावर पासवर्ड आवश्यक आहे"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"अतिरिक्त सुरक्षिततेसाठी पॅटर्न आवश्यक आहे"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"अतिरिक्त सुरक्षिततेसाठी पिन आवश्यक आहे"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"अतिरिक्त सुरक्षिततेसाठी पासवर्ड आवश्यक आहे"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"प्रशासकाद्वारे लॉक केलेले डिव्हाइस"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"डिव्हाइस मॅन्युअली लॉक केले होते"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ओळखले नाही"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"डीफॉल्ट"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"बबल"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"अॅनालॉग"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 453afc3..a6d1af9 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Corak diperlukan setelah peranti dimulakan semula"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah peranti dimulakan semula"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kata laluan diperlukan setelah peranti dimulakan semula"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Corak diperlukan untuk keselamatan tambahan"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN diperlukan untuk keselamatan tambahan"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Kata laluan diperlukan untuk keselamatan tambahan"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Peranti dikunci oleh pentadbir"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Peranti telah dikunci secara manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Lalai"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Gelembung"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 1cc46b1..5617a11 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် ပုံစံ လိုအပ်ပါသည်"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် ပင်နံပါတ် လိုအပ်ပါသည်"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် စကားဝှက် လိုအပ်ပါသည်"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ပိုမို၍ လုံခြုံမှု ရှိစေရန် ပုံစံ လိုအပ်ပါသည်"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ပိုမို၍ လုံခြုံမှု ရှိစေရန် ပင်နံပါတ် လိုအပ်ပါသည်"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ပိုမို၍ လုံခြုံမှု ရှိစေရန် စကားဝှက် လိုအပ်ပါသည်"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"စက်ပစ္စည်းကို စီမံခန့်ခွဲသူက လော့ခ်ချထားပါသည်"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"စက်ပစ္စည်းကို ကိုယ်တိုင်ကိုယ်ကျ လော့ခ်ချထားခဲ့သည်"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"မသိ"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"မူလ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ပူဖောင်းကွက်"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ရိုးရိုး"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 5310a730..0ad9e95 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du må tegne mønsteret etter at enheten har startet på nytt"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du må skrive inn PIN-koden etter at enheten har startet på nytt"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du må skrive inn passordet etter at enheten har startet på nytt"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Du må tegne mønsteret for ekstra sikkerhet"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Du må skrive inn PIN-koden for ekstra sikkerhet"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Du må skrive inn passordet for ekstra sikkerhet"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheten er låst av administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten ble låst manuelt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke gjenkjent"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Boble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 534164b..196b74a 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"यन्त्र पुनः सुरु भएपछि ढाँचा आवश्यक पर्दछ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"यन्त्र पुनः सुरु भएपछि PIN आवश्यक पर्दछ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"यन्त्र पुनः सुरु भएपछि पासवर्ड आवश्यक पर्दछ"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"अतिरिक्त सुरक्षाको लागि ढाँचा आवश्यक छ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"अतिरिक्त सुरक्षाको लागि PIN आवश्यक छ"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"अतिरिक्त सुरक्षाको लागि पासवर्ड आवश्यक छ"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"प्रशासकले यन्त्रलाई लक गर्नुभएको छ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"यन्त्रलाई म्यानुअल तरिकाले लक गरिएको थियो"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहिचान भएन"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"डिफल्ट"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"बबल"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"एनालग"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 08e226d4..747b3bb 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon vereist nadat het apparaat opnieuw is opgestart"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pincode vereist nadat het apparaat opnieuw is opgestart"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wachtwoord vereist nadat het apparaat opnieuw is opgestart"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Patroon vereist voor extra beveiliging"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Pincode vereist voor extra beveiliging"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Wachtwoord vereist voor extra beveiliging"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Apparaat vergrendeld door beheerder"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Apparaat is handmatig vergrendeld"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Niet herkend"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standaard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bel"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 3cdd264..75f7a89 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ଡିଭାଇସ୍ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ ପାଟର୍ନ ଆବଶ୍ୟକ ଅଟେ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ଡିଭାଇସ୍ ରିଷ୍ଟାର୍ଟ ହେବାପରେ ପାସ୍ୱର୍ଡ ଆବଶ୍ୟକ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ଡିଭାଇସ୍ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ ପାସୱର୍ଡ ଆବଶ୍ୟକ ଅଟେ"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ ପାଟର୍ନ ଆବଶ୍ୟକ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ PIN ଆବଶ୍ୟକ ଅଟେ"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ ପାସ୍ୱର୍ଡ ଆବଶ୍ୟକ"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ, ଏହା ପରିବର୍ତ୍ତେ ପାଟର୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ, ଏହା ପରିବର୍ତ୍ତେ PIN ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ, ଏହା ପରିବର୍ତ୍ତେ ପାସୱାର୍ଡ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ଡିଭାଇସ୍ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଲକ୍ କରାଯାଇଛି"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ଡିଭାଇସ୍ ମାନୁଆଲ ଭାବେ ଲକ୍ କରାଗଲା"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ଡିଫଲ୍ଟ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ବବଲ୍"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ଆନାଲଗ୍"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ଜାରି ରଖିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ଅନଲକ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 409f727..bf1a359a 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪਿੰਨ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੈ"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੈ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ ਪਿੰਨ ਦੀ ਲੋੜ ਹੈ"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੈ"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਡੀਵਾਈਸ ਨੂੰ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ਡੀਵਾਈਸ ਨੂੰ ਹੱਥੀਂ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ਬੁਲਬੁਲਾ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ਐਨਾਲੌਗ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 52bc982..c49149b 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po ponownym uruchomieniu urządzenia wymagany jest wzór"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po ponownym uruchomieniu urządzenia wymagany jest kod PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po ponownym uruchomieniu urządzenia wymagane jest hasło"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Dla większego bezpieczeństwa musisz narysować wzór"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Dla większego bezpieczeństwa musisz podać kod PIN"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Dla większego bezpieczeństwa musisz podać hasło"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Urządzenie zablokowane przez administratora"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Urządzenie zostało zablokowane ręcznie"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie rozpoznano"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Domyślna"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bąbelkowy"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogowy"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index b934826..3d60e8c 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"O padrão é exigido após a reinicialização do dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"O PIN é exigido após a reinicialização do dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"A senha é exigida após a reinicialização do dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"O padrão é necessário para aumentar a segurança"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"O PIN é necessário para aumentar a segurança"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"A senha é necessária para aumentar a segurança"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para ter mais segurança, use o padrão"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para ter mais segurança, use o PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para ter mais segurança, use a senha"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Padrão"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolha"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloqueie o dispositivo para continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index a67bfb0..0a94349 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"É necessário um padrão após reiniciar o dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"É necessário um PIN após reiniciar o dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"É necessária uma palavra-passe após reiniciar o dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Para segurança adicional, é necessário um padrão"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Para segurança adicional, é necessário um PIN"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Para segurança adicional, é necessária uma palavra-passe"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para uma segurança adicional, use antes o padrão"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para uma segurança adicional, use antes o PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para uma segurança adicional, use antes a palavra-passe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo gestor"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predefinido"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balão"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloqueie o dispositivo para continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index b934826..3d60e8c 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"O padrão é exigido após a reinicialização do dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"O PIN é exigido após a reinicialização do dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"A senha é exigida após a reinicialização do dispositivo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"O padrão é necessário para aumentar a segurança"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"O PIN é necessário para aumentar a segurança"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"A senha é necessária para aumentar a segurança"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para ter mais segurança, use o padrão"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para ter mais segurança, use o PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para ter mais segurança, use a senha"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Padrão"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolha"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloqueie o dispositivo para continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 5ee67d91..547224e 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Modelul este necesar după repornirea dispozitivului"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Codul PIN este necesar după repornirea dispozitivului"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Parola este necesară după repornirea dispozitivului"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Modelul este necesar pentru securitate suplimentară"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Codul PIN este necesar pentru securitate suplimentară"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Parola este necesară pentru securitate suplimentară"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispozitiv blocat de administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Dispozitivul a fost blocat manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nu este recunoscut"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Prestabilit"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balon"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogic"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 2b8f8d6..f1945ad 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"После перезагрузки устройства необходимо ввести графический ключ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"После перезагрузки устройства необходимо ввести PIN-код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"После перезагрузки устройства необходимо ввести пароль"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"В качестве дополнительной меры безопасности введите графический ключ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"В качестве дополнительной меры безопасности введите PIN-код"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"В качестве дополнительной меры безопасности введите пароль"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"В целях дополнительной безопасности используйте графический ключ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"В целях дополнительной безопасности используйте PIN-код"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"В целях дополнительной безопасности используйте пароль"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Устройство заблокировано администратором"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Устройство было заблокировано вручную"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не распознано"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"По умолчанию"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Пузырь"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Стрелки"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Чтобы продолжить, разблокируйте устройство"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 4e911de..e5862c3 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"උපාංගය නැවත ආරම්භ වූ පසු රටාව අවශ්යයි"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"උපාංගය නැවත ආරම්භ වූ පසු PIN අංකය අවශ්යයි"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"උපාංගය නැවත ආරම්භ වූ පසු මුරපදය අවශ්යයි"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"අමතර ආරක්ෂාව සඳහා රටාව අවශ්යයි"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"අමතර ආරක්ෂාව සඳහා PIN අංකය අවශ්යයි"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"අමතර ආරක්ෂාව සඳහා මුරපදය අවශ්යයි"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ඔබගේ පරිපාලක විසින් උපාංගය අගුළු දමා ඇත"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"උපාංගය හස්තීයව අගුලු දමන ලදී"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"හඳුනා නොගන්නා ලදී"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"පෙරනිමි"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"බුබුළ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ප්රතිසමය"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index f2d68e3..efe4ec8 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po reštartovaní zariadenia musíte zadať bezpečnostný vzor"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po reštartovaní zariadenia musíte zadať kód PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po reštartovaní zariadenia musíte zadať heslo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Na ďalšie zabezpečenie musíte zadať bezpečnostný vzor"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Na ďalšie zabezpečenie musíte zadať kód PIN"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Na ďalšie zabezpečenie musíte zadať heslo"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zariadenie zamkol správca"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zariadenie bolo uzamknuté ručne"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznané"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predvolený"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bublina"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógový"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 772308f..52726c2 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po vnovičnem zagonu naprave je treba vnesti vzorec"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po vnovičnem zagonu naprave je treba vnesti kodo PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po vnovičnem zagonu naprave je treba vnesti geslo"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Zaradi dodatne varnosti morate vnesti vzorec"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Zaradi dodatne varnosti morate vnesti kodo PIN"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Zaradi dodatne varnosti morate vnesti geslo"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Napravo je zaklenil skrbnik"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Naprava je bila ročno zaklenjena"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ni prepoznano"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Privzeto"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mehurček"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogno"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index c758462..a0a5594 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kërkohet motivi pas rinisjes së pajisjes"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Kërkohet kodi PIN pas rinisjes së pajisjes"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kërkohet fjalëkalimi pas rinisjes së pajisjes"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Kërkohet motivi për më shumë siguri"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Kërkohet kodi PIN për më shumë siguri"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Kërkohet fjalëkalimi për më shumë siguri"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Pajisja është e kyçur nga administratori"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Pajisja është kyçur manualisht"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nuk njihet"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"E parazgjedhur"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Flluskë"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoge"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index e6fe853..e634fdcb5 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Треба да унесете шаблон када се уређај поново покрене"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Треба да унесете PIN када се уређај поново покрене"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Треба да унесете лозинку када се уређај поново покрене"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Треба да унесете шаблон ради додатне безбедности"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Треба да унесете PIN ради додатне безбедности"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Треба да унесете лозинку ради додатне безбедности"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Администратор је закључао уређај"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Уређај је ручно закључан"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Није препознат"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Подразумевани"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Мехурићи"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналогни"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index fa241d9..fc9beb1 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste rita mönster när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du måste ange pinkod när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du måste ange lösenord när du har startat om enheten"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Du måste rita mönster för ytterligare säkerhet"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Du måste ange pinkod för ytterligare säkerhet"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Du måste ange lösenord för ytterligare säkerhet"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratören har låst enheten"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten har låsts manuellt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Identifierades inte"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubbla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 791bceb..bcab24b 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Unafaa kuchora mchoro baada ya kuwasha kifaa upya"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Unafaa kuweka PIN baada ya kuwasha kifaa upya"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Unafaa kuweka nenosiri baada ya kuwasha kifaa upya"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Mchoro unahitajika ili kuongeza usalama"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"PIN inahitajika ili kuongeza usalama"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Nenosiri linahitajika ili kuongeza usalama."</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Msimamizi amefunga kifaa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Umefunga kifaa mwenyewe"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Haitambuliwi"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Chaguomsingi"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Kiputo"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogi"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 271657d..88d5760 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"சாதனத்தை மீண்டும் தொடங்கியதும், பேட்டர்னை வரைய வேண்டும்"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"சாதனத்தை மீண்டும் தொடங்கியதும், பின்னை உள்ளிட வேண்டும்"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"சாதனத்தை மீண்டும் தொடங்கியதும், கடவுச்சொல்லை உள்ளிட வேண்டும்"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"கூடுதல் பாதுகாப்பிற்கு, பேட்டர்னை வரைய வேண்டும்"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"கூடுதல் பாதுகாப்பிற்கு, பின்னை உள்ளிட வேண்டும்"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"கூடுதல் பாதுகாப்பிற்கு, கடவுச்சொல்லை உள்ளிட வேண்டும்"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"நிர்வாகி சாதனத்தைப் பூட்டியுள்ளார்"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"பயனர் சாதனத்தைப் பூட்டியுள்ளார்"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"அடையாளங்காணபடவில்லை"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"இயல்பு"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"பபிள்"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"அனலாக்"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index f62e667..3a0111a 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత నమూనాను గీయాలి"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"డివైజ్ను పునఃప్రారంభించిన తర్వాత పిన్ నమోదు చేయాలి"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత పాస్వర్డ్ను నమోదు చేయాలి"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"అదనపు సెక్యూరిటీ కోసం ఆకృతి అవసరం"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"అదనపు సెక్యూరిటీ కోసం పిన్ ఎంటర్ చేయాలి"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"అదనపు సెక్యూరిటీ కోసం పాస్వర్డ్ను ఎంటర్ చేయాలి"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"పరికరం నిర్వాహకుల ద్వారా లాక్ చేయబడింది"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"పరికరం మాన్యువల్గా లాక్ చేయబడింది"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"గుర్తించలేదు"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ఆటోమేటిక్"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"బబుల్"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ఎనలాగ్"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 62a83bc..14a65a07 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ต้องวาดรูปแบบหลังจากอุปกรณ์รีสตาร์ท"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ต้องระบุ PIN หลังจากอุปกรณ์รีสตาร์ท"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ต้องป้อนรหัสผ่านหลังจากอุปกรณ์รีสตาร์ท"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"ต้องวาดรูปแบบเพื่อความปลอดภัยเพิ่มเติม"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"ต้องระบุ PIN เพื่อความปลอดภัยเพิ่มเติม"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"ต้องป้อนรหัสผ่านเพื่อความปลอดภัยเพิ่มเติม"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ใช้รูปแบบแทนเพื่อเพิ่มความปลอดภัย"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ใช้ PIN แทนเพื่อเพิ่มความปลอดภัย"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ใช้รหัสผ่านแทนเพื่อเพิ่มความปลอดภัย"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ผู้ดูแลระบบล็อกอุปกรณ์"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"มีการล็อกอุปกรณ์ด้วยตัวเอง"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ไม่รู้จัก"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ค่าเริ่มต้น"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"บับเบิล"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"แอนะล็อก"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ปลดล็อกอุปกรณ์ของคุณเพื่อดำเนินการต่อ"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 524ea47..7936058 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kailangan ng pattern pagkatapos mag-restart ng device"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Kailangan ng PIN pagkatapos mag-restart ng device"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kailangan ng password pagkatapos mag-restart ng device"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Kinakailangan ang pattern para sa karagdagang seguridad"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Kinakailangan ang PIN para sa karagdagang seguridad"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Kinakailangan ang password para sa karagdagang seguridad"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para sa karagdagang seguridad, gumamit na lang ng pattern"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para sa karagdagang seguridad, gumamit na lang ng PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para sa karagdagang seguridad, gumamit na lang ng password"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Na-lock ng admin ang device"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Manual na na-lock ang device"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Hindi nakilala"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"I-unlock ang iyong device para magpatuloy"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 54aaae3..e520762 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cihaz yeniden başladıktan sonra desen gerekir"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cihaz yeniden başladıktan sonra PIN gerekir"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cihaz yeniden başladıktan sonra şifre gerekir"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Ek güvenlik için desen gerekir"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Ek güvenlik için PIN gerekir"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Ek güvenlik için şifre gerekir"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz, yönetici tarafından kilitlendi"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihazın manuel olarak kilitlendi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmadı"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Varsayılan"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Baloncuk"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 6144c1c..613181d 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Після перезавантаження пристрою потрібно ввести ключ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Після перезавантаження пристрою потрібно ввести PIN-код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Після перезавантаження пристрою потрібно ввести пароль"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Для додаткового захисту потрібно ввести ключ"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Для додаткового захисту потрібно ввести PIN-код"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Для додаткового захисту потрібно ввести пароль"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Адміністратор заблокував пристрій"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Пристрій заблоковано вручну"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не розпізнано"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"За умовчанням"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Бульбашковий"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналоговий"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 4e77841..a122f85 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"آلہ دوبارہ چالو ہونے کے بعد پیٹرن درکار ہوتا ہے"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"آلہ دوبارہ چالو ہونے کے بعد PIN درکار ہوتا ہے"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"آلہ دوبارہ چالو ہونے کے بعد پاس ورڈ درکار ہوتا ہے"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"اضافی سیکیورٹی کیلئے پیٹرن درکار ہے"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"اضافی سیکیورٹی کیلئے PIN درکار ہے"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"اضافی سیکیورٹی کیلئے پاس ورڈ درکار ہے"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"آلہ منتظم کی جانب سے مقفل ہے"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"آلہ کو دستی طور پر مقفل کیا گیا تھا"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"تسلیم شدہ نہیں ہے"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"ڈیفالٹ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"بلبلہ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"اینالاگ"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index afaf746..2cc9724 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -78,9 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Qurilma qayta ishga tushganidan keyin grafik kalitni kiritish zarur"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Qurilma qayta ishga tushganidan keyin PIN kodni kiritish zarur"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Qurilma qayta ishga tushganidan keyin parolni kiritish zarur"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Qo‘shimcha xavfsizlik chorasi sifatida grafik kalit talab qilinadi"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Qo‘shimcha xavfsizlik chorasi sifatida PIN kod talab qilinadi"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Qo‘shimcha xavfsizlik chorasi sifatida parol talab qilinadi"</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Qoʻshimcha xavfsizlik maqsadida oʻrniga grafik kalitdan foydalaning"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Qoʻshimcha xavfsizlik maqsadida oʻrniga PIN koddan foydalaning"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Qoʻshimcha xavfsizlik maqsadida oʻrniga paroldan foydalaning"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Qurilma administrator tomonidan bloklangan"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Qurilma qo‘lda qulflangan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Aniqlanmadi"</string>
@@ -90,4 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Odatiy"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Pufaklar"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Davom etish uchun qurilmangizni qulfdan chiqaring"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 1d6cfa8..e7c9295 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Yêu cầu hình mở khóa sau khi thiết bị khởi động lại"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Yêu cầu mã PIN sau khi thiết bị khởi động lại"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Yêu cầu mật khẩu sau khi thiết bị khởi động lại"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Yêu cầu hình mở khóa để bảo mật thêm"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Yêu cầu mã PIN để bảo mật thêm"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Yêu cầu mật khẩu để bảo mật thêm"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Thiết bị đã bị quản trị viên khóa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Thiết bị đã bị khóa theo cách thủ công"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Không nhận dạng được"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Mặc định"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bong bóng"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Đồng hồ kim"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 8c8507e..d37d645 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"重启设备后需要绘制解锁图案"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"重启设备后需要输入 PIN 码"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"重启设备后需要输入密码"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"需要绘制解锁图案以进一步确保安全"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"需要输入 PIN 码以进一步确保安全"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"需要输入密码以进一步确保安全"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管理员已锁定设备"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"此设备已手动锁定"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"无法识别"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"默认"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"指针"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index c331a92..9dbb8f2 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後,必須畫出上鎖圖案才能使用"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後,必須輸入 PIN 碼才能使用"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後,必須輸入密碼才能使用"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"請務必畫出上鎖圖案,以進一步確保安全"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"請務必輸入 PIN 碼,以進一步確保安全"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"請務必輸入密碼,以進一步確保安全"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"裝置已由管理員鎖定"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"使用者已手動將裝置上鎖"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"未能識別"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"預設"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"指針"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 1e1bec3..ebb88e1 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後需要畫出解鎖圖案"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後需要輸入 PIN 碼"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後需要輸入密碼"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"請畫出解鎖圖案,以進一步確保資訊安全"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"請輸入 PIN 碼,以進一步確保資訊安全"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"請輸入密碼,以進一步確保資訊安全"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管理員已鎖定裝置"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"裝置已手動鎖定"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"無法識別"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"預設"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"類比"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index c8f78ea..57e56f7 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -78,9 +78,12 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Iphethini iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Iphinikhodi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Iphasiwedi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
- <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"Kudingeka iphethini ngokuvikeleka okungeziwe"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"Kudingeka iphinikhodi ngokuvikeleka okungeziwe"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"Iphasiwedi idingelwa ukuvikela okungeziwe"</string>
+ <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
+ <skip />
+ <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
+ <skip />
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Idivayisi ikhiywe ngumlawuli"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Idivayisi ikhiywe ngokwenza"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Akwaziwa"</string>
@@ -90,4 +93,6 @@
<string name="clock_title_default" msgid="6342735240617459864">"Okuzenzekelayo"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Ibhamuza"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"I-Analog"</string>
+ <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/drawable/overlay_badge_background.xml b/packages/SystemUI/res/drawable/overlay_badge_background.xml
new file mode 100644
index 0000000..857632e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/overlay_badge_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="oval">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+</shape>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 5b96159..ae2537f 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -190,6 +190,11 @@
</LinearLayout>
+ <ViewStub android:id="@+id/secondary_mobile_network_stub"
+ android:inflatedId="@+id/secondary_mobile_network_layout"
+ android:layout="@layout/qs_dialog_secondary_mobile_network"
+ style="@style/InternetDialog.Network"/>
+
<LinearLayout
android:id="@+id/turn_on_wifi_layout"
style="@style/InternetDialog.Network"
diff --git a/packages/SystemUI/res/layout/qs_dialog_secondary_mobile_network.xml b/packages/SystemUI/res/layout/qs_dialog_secondary_mobile_network.xml
new file mode 100644
index 0000000..4592c5e
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_dialog_secondary_mobile_network.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/InternetDialog.Network">
+
+ <FrameLayout
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:clickable="false"
+ android:layout_gravity="center_vertical|start">
+ <ImageView
+ android:id="@+id/secondary_signal_icon"
+ android:autoMirrored="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:clickable="false"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="start|center_vertical">
+ <TextView
+ android:id="@+id/secondary_mobile_title"
+ android:maxLines="1"
+ style="@style/InternetDialog.NetworkTitle"/>
+ <TextView
+ android:id="@+id/secondary_mobile_summary"
+ style="@style/InternetDialog.NetworkSummary"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:layout_width="24dp"
+ android:layout_height="match_parent"
+ android:clickable="false"
+ android:layout_gravity="end|center_vertical"
+ android:gravity="center">
+ <ImageView
+ android:id="@+id/secondary_settings_icon"
+ android:src="@drawable/ic_settings_24dp"
+ android:layout_width="24dp"
+ android:layout_gravity="end|center_vertical"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 2fb6d6c..9fc3f40 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -23,6 +23,7 @@
android:layout_height="wrap_content"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:background="@android:color/transparent"
+ android:importantForAccessibility="no"
android:baselineAligned="false"
android:clickable="false"
android:clipChildren="false"
@@ -56,7 +57,7 @@
android:clipToPadding="false"
android:focusable="true"
android:paddingBottom="@dimen/qqs_layout_padding_bottom"
- android:importantForAccessibility="yes">
+ android:importantForAccessibility="no">
</com.android.systemui.qs.QuickQSPanel>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index 60bc373..8b5d953 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -25,6 +25,7 @@
android:gravity="center"
android:layout_gravity="top"
android:orientation="horizontal"
+ android:importantForAccessibility="no"
android:clickable="true"
android:minHeight="48dp">
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 9c02749..1ac78d4 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -103,8 +103,18 @@
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
app:layout_constraintStart_toStartOf="@id/screenshot_preview_border"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"
- app:layout_constraintTop_toTopOf="@id/screenshot_preview_border">
- </ImageView>
+ app:layout_constraintTop_toTopOf="@id/screenshot_preview_border"/>
+ <ImageView
+ android:id="@+id/screenshot_badge"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:padding="4dp"
+ android:visibility="gone"
+ android:background="@drawable/overlay_badge_background"
+ android:elevation="8dp"
+ android:src="@drawable/overlay_cancel"
+ app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
+ app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"/>
<FrameLayout
android:id="@+id/screenshot_dismiss_button"
android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 92ef3f8..159323a 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -42,12 +42,6 @@
android:clipToPadding="false"
android:clipChildren="false">
- <ViewStub
- android:id="@+id/qs_header_stub"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- />
-
<include
layout="@layout/keyguard_status_view"
android:visibility="gone"/>
@@ -69,6 +63,15 @@
systemui:layout_constraintBottom_toBottomOf="parent"
/>
+ <!-- This view should be after qs_frame so touches are dispatched first to it. That gives
+ it a chance to capture clicks before the NonInterceptingScrollView disallows all
+ intercepts -->
+ <ViewStub
+ android:id="@+id/qs_header_stub"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ />
+
<androidx.constraintlayout.widget.Guideline
android:id="@+id/qs_edge_guideline"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5f1863a..8a1a9e2 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -672,7 +672,7 @@
<string name="data_connection_no_internet" msgid="691058178914184544">"沒有網際網路連線"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"編輯設定順序。"</string>
- <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源按鈕選單"</string>
+ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源鍵選單"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"鎖定畫面"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"手機先前過熱,因此關閉電源"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d4d8843..44031bb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2022,6 +2022,15 @@
<!-- Text used to refer to the user's current carrier in mobile_data_disable_message if the users's mobile network carrier name is not available [CHAR LIMIT=NONE] -->
<string name="mobile_data_disable_message_default_carrier">your carrier</string>
+ <!-- Title of the dialog to turn off data usage [CHAR LIMIT=NONE] -->
+ <string name="auto_data_switch_disable_title">Switch back to <xliff:g id="carrier" example="T-Mobile">%s</xliff:g>?</string>
+ <!-- Message body of the dialog to turn off data usage [CHAR LIMIT=NONE] -->
+ <string name="auto_data_switch_disable_message">Mobile data won\’t automatically switch based on availability</string>
+ <!-- Negative button title of the quick settings switch back to DDS dialog [CHAR LIMIT=NONE] -->
+ <string name="auto_data_switch_dialog_negative_button">No thanks</string>
+ <!-- Positive button title of the quick settings switch back to DDS dialog [CHAR LIMIT=NONE] -->
+ <string name="auto_data_switch_dialog_positive_button">Yes, switch</string>
+
<!-- Warning shown when user input has been blocked due to another app overlaying screen
content. Since we don't know what the app is showing on top of the input target, we
can't verify user consent. [CHAR LIMIT=NONE] -->
@@ -2527,6 +2536,12 @@
Summary indicating that a SIM has an active mobile data connection [CHAR LIMIT=50] -->
<string name="mobile_data_connection_active">Connected</string>
<!-- Provider Model:
+ Summary indicating that a SIM is temporarily connected to mobile data [CHAR LIMIT=50] -->
+ <string name="mobile_data_temp_connection_active">Temporarily connected</string>
+ <!-- Provider Model:
+ Summary indicating that a SIM is temporarily connected to mobile data [CHAR LIMIT=50] -->
+ <string name="mobile_data_poor_connection">Poor connection</string>
+ <!-- Provider Model:
Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] -->
<string name="mobile_data_off_summary">Mobile data won\u0027t auto\u2011connect</string>
<!-- Provider Model:
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index cd27263..48821e8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -18,7 +18,6 @@
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Handler
-import android.os.UserHandle
import android.provider.Settings
import android.util.Log
import com.android.internal.annotations.Keep
@@ -39,15 +38,15 @@
val context: Context,
val pluginManager: PluginManager,
val handler: Handler,
- defaultClockProvider: ClockProvider
+ val isEnabled: Boolean,
+ userHandle: Int,
+ defaultClockProvider: ClockProvider,
) {
// Usually this would be a typealias, but a SAM provides better java interop
fun interface ClockChangeListener {
fun onClockChanged()
}
- var isEnabled: Boolean = false
-
private val gson = Gson()
private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
private val clockChangeListeners = mutableListOf<ClockChangeListener>()
@@ -97,14 +96,19 @@
)
}
- pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java,
- true /* allowMultiple */)
- context.contentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
- false,
- settingObserver,
- UserHandle.USER_ALL
- )
+ if (isEnabled) {
+ pluginManager.addPluginListener(
+ pluginListener,
+ ClockProviderPlugin::class.java,
+ /*allowMultiple=*/ true
+ )
+ context.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+ /*notifyForDescendants=*/ false,
+ settingObserver,
+ userHandle
+ )
+ }
}
private fun connectClocks(provider: ClockProvider) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 8eebe30..ace942d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -37,8 +37,6 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
@@ -120,8 +118,7 @@
SecureSettings secureSettings,
@Main Executor uiExecutor,
DumpManager dumpManager,
- ClockEventController clockEventController,
- FeatureFlags featureFlags) {
+ ClockEventController clockEventController) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mClockRegistry = clockRegistry;
@@ -134,7 +131,6 @@
mDumpManager = dumpManager;
mClockEventController = clockEventController;
- mClockRegistry.setEnabled(featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS));
mClockChangedListener = () -> {
setClock(mClockRegistry.createCurrentClock());
};
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index f43f559..9767313 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -18,10 +18,13 @@
import android.content.Context;
import android.os.Handler;
+import android.os.UserHandle;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.clocks.DefaultClockProvider;
import com.android.systemui.shared.plugins.PluginManager;
@@ -39,7 +42,14 @@
@Application Context context,
PluginManager pluginManager,
@Main Handler handler,
- DefaultClockProvider defaultClockProvider) {
- return new ClockRegistry(context, pluginManager, handler, defaultClockProvider);
+ DefaultClockProvider defaultClockProvider,
+ FeatureFlags featureFlags) {
+ return new ClockRegistry(
+ context,
+ pluginManager,
+ handler,
+ featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
+ UserHandle.USER_ALL,
+ defaultClockProvider);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 9f1c9b4..0a2dc5b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -597,6 +597,7 @@
case INTENT_ACTION_DPAD_CENTER: {
Intent intent = new Intent(intentAction);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
return PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_IMMUTABLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 3e796cd0..b50bfd7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -127,7 +127,7 @@
private final ScrollView mBiometricScrollView;
private final View mPanelView;
private final float mTranslationY;
- @ContainerState private int mContainerState = STATE_UNKNOWN;
+ @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
private final Set<Integer> mFailedModalities = new HashSet<Integer>();
private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
@@ -630,11 +630,25 @@
wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
}
+ private void forceExecuteAnimatedIn() {
+ if (mContainerState == STATE_ANIMATING_IN) {
+ //clear all animators
+ if (mCredentialView != null && mCredentialView.isAttachedToWindow()) {
+ mCredentialView.animate().cancel();
+ }
+ mPanelView.animate().cancel();
+ mBiometricView.animate().cancel();
+ animate().cancel();
+ onDialogAnimatedIn();
+ }
+ }
+
@Override
public void dismissWithoutCallback(boolean animate) {
if (animate) {
animateAway(false /* sendReason */, 0 /* reason */);
} else {
+ forceExecuteAnimatedIn();
removeWindowIfAttached();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 3620ba7..3c11679 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -132,7 +132,7 @@
@Deprecated("Not needed anymore") val NEW_USER_SWITCHER = ReleasedFlag(500)
// TODO(b/254512321): Tracking Bug
- @JvmField val COMBINED_QS_HEADERS = UnreleasedFlag(501, teamfood = true)
+ @JvmField val COMBINED_QS_HEADERS = ReleasedFlag(501, teamfood = true)
val PEOPLE_TILE = ResourceBooleanFlag(502, R.bool.flag_conversations)
@JvmField
val QS_USER_DETAIL_SHORTCUT =
@@ -142,7 +142,7 @@
@Deprecated("Not needed anymore") val NEW_FOOTER = ReleasedFlag(504)
// TODO(b/254512747): Tracking Bug
- val NEW_HEADER = UnreleasedFlag(505, teamfood = true)
+ val NEW_HEADER = ReleasedFlag(505, teamfood = true)
// TODO(b/254512383): Tracking Bug
@JvmField
@@ -152,6 +152,9 @@
// TODO(b/254512678): Tracking Bug
@JvmField val NEW_FOOTER_ACTIONS = ReleasedFlag(507)
+ // TODO(b/244064524): Tracking Bug
+ @JvmField val QS_SECONDARY_DATA_SUB_INFO = UnreleasedFlag(508, teamfood = true)
+
// 600- status bar
// TODO(b/254513246): Tracking Bug
val STATUS_BAR_USER_SWITCHER = ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0d74dc8..480fd93 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -91,6 +91,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
@@ -322,6 +323,12 @@
// true if the keyguard is hidden by another window
private boolean mOccluded = false;
+ /**
+ * Whether the {@link #mOccludeAnimationController} is currently playing the occlusion
+ * animation.
+ */
+ private boolean mOccludeAnimationPlaying = false;
+
private boolean mWakeAndUnlocking = false;
/**
@@ -837,15 +844,22 @@
/**
* Animation launch controller for activities that occlude the keyguard.
*/
- private final ActivityLaunchAnimator.Controller mOccludeAnimationController =
+ @VisibleForTesting
+ final ActivityLaunchAnimator.Controller mOccludeAnimationController =
new ActivityLaunchAnimator.Controller() {
@Override
- public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {}
+ public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
+ mOccludeAnimationPlaying = true;
+ }
@Override
public void onLaunchAnimationCancelled(@Nullable Boolean newKeyguardOccludedState) {
Log.d(TAG, "Occlude launch animation cancelled. Occluded state is now: "
+ mOccluded);
+ mOccludeAnimationPlaying = false;
+
+ // Ensure keyguard state is set correctly if we're cancelled.
+ mCentralSurfaces.updateIsKeyguard();
}
@Override
@@ -854,6 +868,12 @@
mCentralSurfaces.instantCollapseNotificationPanel();
}
+ mOccludeAnimationPlaying = false;
+
+ // Hide the keyguard now that we're done launching the occluding activity over
+ // it.
+ mCentralSurfaces.updateIsKeyguard();
+
mInteractionJankMonitor.end(CUJ_LOCKSCREEN_OCCLUSION);
}
@@ -1768,6 +1788,10 @@
return mShowing && !mOccluded;
}
+ public boolean isOccludeAnimationPlaying() {
+ return mOccludeAnimationPlaying;
+ }
+
/**
* Notify us when the keyguard is occluded by another window
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
index 38c971e..120f7d6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
@@ -43,6 +43,21 @@
)
}
+ /**
+ * Logs an error in trying to update to [displayState].
+ *
+ * [displayState] is either a [android.app.StatusBarManager.MediaTransferSenderState] or
+ * a [android.app.StatusBarManager.MediaTransferReceiverState].
+ */
+ fun logStateChangeError(displayState: Int) {
+ buffer.log(
+ tag,
+ LogLevel.ERROR,
+ { int1 = displayState },
+ { "Cannot display state=$int1; aborting" }
+ )
+ }
+
/** Logs that we couldn't find information for [packageName]. */
fun logPackageNotFound(packageName: String) {
buffer.log(
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 089625c..dc794e6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -25,7 +25,6 @@
import android.media.MediaRoute2Info
import android.os.Handler
import android.os.PowerManager
-import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
@@ -116,7 +115,7 @@
logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName)
if (chipState == null) {
- Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
+ logger.logStateChangeError(displayState)
return
}
uiEventLogger.logReceiverStateChange(chipState)
@@ -236,5 +235,3 @@
) : TemporaryViewInfo {
override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
}
-
-private const val RECEIVER_TAG = "MediaTapToTransferRcvr"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index edf759d..1fa8fae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -19,7 +19,6 @@
import android.app.StatusBarManager
import android.content.Context
import android.media.MediaRoute2Info
-import android.util.Log
import android.view.View
import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
@@ -34,7 +33,6 @@
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarEndItem
import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo
-import com.android.systemui.temporarydisplay.chipbar.SENDER_TAG
import javax.inject.Inject
/**
@@ -86,7 +84,7 @@
logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName)
if (chipState == null) {
- Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
+ logger.logStateChangeError(displayState)
return
}
uiEventLogger.logSenderStateChange(chipState)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index b6b657e..57a00c9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -204,6 +204,15 @@
Trace.endSection();
}
+ @Override
+ public void onUserListItemClicked(@NonNull UserRecord record,
+ @Nullable UserSwitchDialogController.DialogShower dialogShower) {
+ if (dialogShower != null) {
+ mDialogShower.dismiss();
+ }
+ super.onUserListItemClicked(record, dialogShower);
+ }
+
public void linkToViewGroup(ViewGroup viewGroup) {
PseudoGridView.ViewGroupAdapterBridge.link(viewGroup, this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 24c4723..a895d72 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -39,6 +39,7 @@
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewStub;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
@@ -62,6 +63,7 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -72,6 +74,8 @@
import java.util.List;
import java.util.concurrent.Executor;
+import javax.inject.Inject;
+
/**
* Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
*/
@@ -86,6 +90,7 @@
private final Handler mHandler;
private final Executor mBackgroundExecutor;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
@VisibleForTesting
protected InternetAdapter mAdapter;
@@ -109,6 +114,7 @@
private LinearLayout mInternetDialogLayout;
private LinearLayout mConnectedWifListLayout;
private LinearLayout mMobileNetworkLayout;
+ private LinearLayout mSecondaryMobileNetworkLayout;
private LinearLayout mTurnWifiOnLayout;
private LinearLayout mEthernetLayout;
private TextView mWifiToggleTitleText;
@@ -123,6 +129,8 @@
private ImageView mSignalIcon;
private TextView mMobileTitleText;
private TextView mMobileSummaryText;
+ private TextView mSecondaryMobileTitleText;
+ private TextView mSecondaryMobileSummaryText;
private TextView mAirplaneModeSummaryText;
private Switch mMobileDataToggle;
private View mMobileToggleDivider;
@@ -158,9 +166,11 @@
mInternetDialogSubTitle.setText(getSubtitleText());
};
+ @Inject
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController, boolean canConfigMobileData,
boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
+ DialogLaunchAnimator dialogLaunchAnimator,
@Main Handler handler, @Background Executor executor,
KeyguardStateController keyguardStateController) {
super(context);
@@ -183,6 +193,7 @@
mKeyguard = keyguardStateController;
mUiEventLogger = uiEventLogger;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
mAdapter = new InternetAdapter(mInternetDialogController);
if (!aboveStatusBar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -287,6 +298,9 @@
mMobileNetworkLayout.setOnClickListener(null);
mMobileDataToggle.setOnCheckedChangeListener(null);
mConnectedWifListLayout.setOnClickListener(null);
+ if (mSecondaryMobileNetworkLayout != null) {
+ mSecondaryMobileNetworkLayout.setOnClickListener(null);
+ }
mSeeAllLayout.setOnClickListener(null);
mWiFiToggle.setOnCheckedChangeListener(null);
mDoneButton.setOnClickListener(null);
@@ -341,6 +355,10 @@
private void setOnClickListener() {
mMobileNetworkLayout.setOnClickListener(v -> {
+ int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+ if (autoSwitchNonDdsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ showTurnOffAutoDataSwitchDialog(autoSwitchNonDdsSubId);
+ }
mInternetDialogController.connectCarrierNetwork();
});
mMobileDataToggle.setOnCheckedChangeListener(
@@ -385,11 +403,14 @@
if (!mInternetDialogController.hasActiveSubId()
&& (!isWifiEnabled || !isCarrierNetworkActive)) {
mMobileNetworkLayout.setVisibility(View.GONE);
+ if (mSecondaryMobileNetworkLayout != null) {
+ mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
+ }
} else {
mMobileNetworkLayout.setVisibility(View.VISIBLE);
mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
- mMobileTitleText.setText(getMobileNetworkTitle());
- String summary = getMobileNetworkSummary();
+ mMobileTitleText.setText(getMobileNetworkTitle(mDefaultDataSubId));
+ String summary = getMobileNetworkSummary(mDefaultDataSubId);
if (!TextUtils.isEmpty(summary)) {
mMobileSummaryText.setText(
Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
@@ -399,28 +420,11 @@
mMobileSummaryText.setVisibility(View.GONE);
}
mBackgroundExecutor.execute(() -> {
- Drawable drawable = getSignalStrengthDrawable();
+ Drawable drawable = getSignalStrengthDrawable(mDefaultDataSubId);
mHandler.post(() -> {
mSignalIcon.setImageDrawable(drawable);
});
});
- mMobileTitleText.setTextAppearance(isNetworkConnected
- ? R.style.TextAppearance_InternetDialog_Active
- : R.style.TextAppearance_InternetDialog);
- int secondaryRes = isNetworkConnected
- ? R.style.TextAppearance_InternetDialog_Secondary_Active
- : R.style.TextAppearance_InternetDialog_Secondary;
- mMobileSummaryText.setTextAppearance(secondaryRes);
- // Set airplane mode to the summary for carrier network
- if (mInternetDialogController.isAirplaneModeEnabled()) {
- mAirplaneModeSummaryText.setVisibility(View.VISIBLE);
- mAirplaneModeSummaryText.setText(mContext.getText(R.string.airplane_mode));
- mAirplaneModeSummaryText.setTextAppearance(secondaryRes);
- } else {
- mAirplaneModeSummaryText.setVisibility(View.GONE);
- }
- mMobileNetworkLayout.setBackground(
- isNetworkConnected ? mBackgroundOn : mBackgroundOff);
TypedArray array = mContext.obtainStyledAttributes(
R.style.InternetDialog_Divider_Active, new int[]{android.R.attr.background});
@@ -433,6 +437,86 @@
mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
mMobileToggleDivider.setVisibility(
mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
+
+ // Display the info for the non-DDS if it's actively being used
+ int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+ int nonDdsVisibility = autoSwitchNonDdsSubId
+ != SubscriptionManager.INVALID_SUBSCRIPTION_ID ? View.VISIBLE : View.GONE;
+
+ int secondaryRes = isNetworkConnected
+ ? R.style.TextAppearance_InternetDialog_Secondary_Active
+ : R.style.TextAppearance_InternetDialog_Secondary;
+ if (nonDdsVisibility == View.VISIBLE) {
+ // non DDS is the currently active sub, set primary visual for it
+ ViewStub stub = mDialogView.findViewById(R.id.secondary_mobile_network_stub);
+ if (stub != null) {
+ stub.inflate();
+ }
+ mSecondaryMobileNetworkLayout = findViewById(R.id.secondary_mobile_network_layout);
+ mSecondaryMobileNetworkLayout.setOnClickListener(
+ this::onClickConnectedSecondarySub);
+ mSecondaryMobileNetworkLayout.setBackground(mBackgroundOn);
+
+ mSecondaryMobileTitleText = mDialogView.requireViewById(
+ R.id.secondary_mobile_title);
+ mSecondaryMobileTitleText.setText(getMobileNetworkTitle(autoSwitchNonDdsSubId));
+ mSecondaryMobileTitleText.setTextAppearance(
+ R.style.TextAppearance_InternetDialog_Active);
+
+ mSecondaryMobileSummaryText =
+ mDialogView.requireViewById(R.id.secondary_mobile_summary);
+ summary = getMobileNetworkSummary(autoSwitchNonDdsSubId);
+ if (!TextUtils.isEmpty(summary)) {
+ mSecondaryMobileSummaryText.setText(
+ Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
+ mSecondaryMobileSummaryText.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
+ mSecondaryMobileSummaryText.setTextAppearance(
+ R.style.TextAppearance_InternetDialog_Active);
+ }
+
+ ImageView mSecondarySignalIcon =
+ mDialogView.requireViewById(R.id.secondary_signal_icon);
+ mBackgroundExecutor.execute(() -> {
+ Drawable drawable = getSignalStrengthDrawable(autoSwitchNonDdsSubId);
+ mHandler.post(() -> {
+ mSecondarySignalIcon.setImageDrawable(drawable);
+ });
+ });
+
+ ImageView mSecondaryMobileSettingsIcon =
+ mDialogView.requireViewById(R.id.secondary_settings_icon);
+ mSecondaryMobileSettingsIcon.setColorFilter(
+ mContext.getColor(R.color.connected_network_primary_color));
+
+ // set secondary visual for default data sub
+ mMobileNetworkLayout.setBackground(mBackgroundOff);
+ mMobileTitleText.setTextAppearance(R.style.TextAppearance_InternetDialog);
+ mMobileSummaryText.setTextAppearance(
+ R.style.TextAppearance_InternetDialog_Secondary);
+ mSignalIcon.setColorFilter(
+ mContext.getColor(R.color.connected_network_secondary_color));
+ } else {
+ mMobileNetworkLayout.setBackground(
+ isNetworkConnected ? mBackgroundOn : mBackgroundOff);
+ mMobileTitleText.setTextAppearance(isNetworkConnected
+ ?
+ R.style.TextAppearance_InternetDialog_Active
+ : R.style.TextAppearance_InternetDialog);
+ mMobileSummaryText.setTextAppearance(secondaryRes);
+ }
+
+ if (mSecondaryMobileNetworkLayout != null) {
+ mSecondaryMobileNetworkLayout.setVisibility(nonDdsVisibility);
+ }
+
+ // Set airplane mode to the summary for carrier network
+ if (mInternetDialogController.isAirplaneModeEnabled()) {
+ mAirplaneModeSummaryText.setVisibility(View.VISIBLE);
+ mAirplaneModeSummaryText.setText(mContext.getText(R.string.airplane_mode));
+ mAirplaneModeSummaryText.setTextAppearance(secondaryRes);
+ } else {
+ mAirplaneModeSummaryText.setVisibility(View.GONE);
+ }
}
}
@@ -471,6 +555,10 @@
mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
mWifiSettingsIcon.setColorFilter(
mContext.getColor(R.color.connected_network_primary_color));
+
+ if (mSecondaryMobileNetworkLayout != null) {
+ mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
+ }
}
@MainThread
@@ -541,6 +629,11 @@
mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
}
+ /** For DSDS auto data switch **/
+ void onClickConnectedSecondarySub(View view) {
+ mInternetDialogController.launchMobileNetworkSettings(view);
+ }
+
void onClickSeeMoreButton(View view) {
mInternetDialogController.launchNetworkSetting(view);
}
@@ -555,16 +648,16 @@
mIsProgressBarVisible && !mIsSearchingHidden);
}
- private Drawable getSignalStrengthDrawable() {
- return mInternetDialogController.getSignalStrengthDrawable();
+ private Drawable getSignalStrengthDrawable(int subId) {
+ return mInternetDialogController.getSignalStrengthDrawable(subId);
}
- CharSequence getMobileNetworkTitle() {
- return mInternetDialogController.getMobileNetworkTitle();
+ CharSequence getMobileNetworkTitle(int subId) {
+ return mInternetDialogController.getMobileNetworkTitle(subId);
}
- String getMobileNetworkSummary() {
- return mInternetDialogController.getMobileNetworkSummary();
+ String getMobileNetworkSummary(int subId) {
+ return mInternetDialogController.getMobileNetworkSummary(subId);
}
protected void showProgressBar() {
@@ -602,8 +695,8 @@
}
private void showTurnOffMobileDialog() {
- CharSequence carrierName = getMobileNetworkTitle();
- boolean isInService = mInternetDialogController.isVoiceStateInService();
+ CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
+ boolean isInService = mInternetDialogController.isVoiceStateInService(mDefaultDataSubId);
if (TextUtils.isEmpty(carrierName) || !isInService) {
carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
}
@@ -627,7 +720,33 @@
SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
SystemUIDialog.registerDismissListener(mAlertDialog);
SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
- mAlertDialog.show();
+ mDialogLaunchAnimator.showFromDialog(mAlertDialog, this, null, false);
+ }
+
+ private void showTurnOffAutoDataSwitchDialog(int subId) {
+ CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
+ if (TextUtils.isEmpty(carrierName)) {
+ carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
+ }
+ mAlertDialog = new Builder(mContext)
+ .setTitle(mContext.getString(R.string.auto_data_switch_disable_title, carrierName))
+ .setMessage(R.string.auto_data_switch_disable_message)
+ .setNegativeButton(R.string.auto_data_switch_dialog_negative_button,
+ (d, w) -> {})
+ .setPositiveButton(R.string.auto_data_switch_dialog_positive_button,
+ (d, w) -> {
+ mInternetDialogController
+ .setAutoDataSwitchMobileDataPolicy(subId, false);
+ if (mSecondaryMobileNetworkLayout != null) {
+ mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
+ }
+ })
+ .create();
+ mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
+ SystemUIDialog.registerDismissListener(mAlertDialog);
+ SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
+ mDialogLaunchAnimator.showFromDialog(mAlertDialog, this, null, false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 0e00c46..aa6e678 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -37,6 +37,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.wifi.WifiManager;
+import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
@@ -78,6 +79,8 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -90,6 +93,7 @@
import com.android.wifitrackerlib.WifiEntry;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -113,6 +117,17 @@
"android.settings.NETWORK_PROVIDER_SETTINGS";
private static final String ACTION_WIFI_SCANNING_SETTINGS =
"android.settings.WIFI_SCANNING_SETTINGS";
+ /**
+ * Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS}
+ */
+ private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+ /**
+ * When starting this activity, this extra can also be specified to supply a Bundle of arguments
+ * to pass to that fragment when it is instantiated during the initial creation of the activity.
+ */
+ private static final String SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS =
+ ":settings:show_fragment_args";
+ private static final String AUTO_DATA_SWITCH_SETTING_R_ID = "auto_data_switch";
public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
public static final int NO_CELL_DATA_TYPE_ICON = 0;
private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off;
@@ -130,9 +145,12 @@
static final int MAX_WIFI_ENTRY_COUNT = 3;
+ private final FeatureFlags mFeatureFlags;
+
private WifiManager mWifiManager;
private Context mContext;
private SubscriptionManager mSubscriptionManager;
+ private Map<Integer, TelephonyManager> mSubIdTelephonyManagerMap = new HashMap<>();
private TelephonyManager mTelephonyManager;
private ConnectivityManager mConnectivityManager;
private CarrierConfigTracker mCarrierConfigTracker;
@@ -155,6 +173,7 @@
private WindowManager mWindowManager;
private ToastFactory mToastFactory;
private SignalDrawable mSignalDrawable;
+ private SignalDrawable mSecondarySignalDrawable; // For the secondary mobile data sub in DSDS
private LocationController mLocationController;
private DialogLaunchAnimator mDialogLaunchAnimator;
private boolean mHasWifiEntries;
@@ -213,7 +232,8 @@
CarrierConfigTracker carrierConfigTracker,
LocationController locationController,
DialogLaunchAnimator dialogLaunchAnimator,
- WifiStateWorker wifiStateWorker
+ WifiStateWorker wifiStateWorker,
+ FeatureFlags featureFlags
) {
if (DEBUG) {
Log.d(TAG, "Init InternetDialogController");
@@ -242,10 +262,12 @@
mWindowManager = windowManager;
mToastFactory = toastFactory;
mSignalDrawable = new SignalDrawable(mContext);
+ mSecondarySignalDrawable = new SignalDrawable(mContext);
mLocationController = locationController;
mDialogLaunchAnimator = dialogLaunchAnimator;
mConnectedWifiInternetMonitor = new ConnectedWifiInternetMonitor();
mWifiStateWorker = wifiStateWorker;
+ mFeatureFlags = featureFlags;
}
void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
@@ -267,6 +289,7 @@
}
mConfig = MobileMappings.Config.readConfig(mContext);
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
+ mSubIdTelephonyManagerMap.put(mDefaultDataSubId, mTelephonyManager);
mInternetTelephonyCallback = new InternetTelephonyCallback();
mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback);
// Listen the connectivity changes
@@ -280,7 +303,9 @@
Log.d(TAG, "onStop");
}
mBroadcastDispatcher.unregisterReceiver(mConnectionStateReceiver);
- mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
+ for (TelephonyManager tm : mSubIdTelephonyManagerMap.values()) {
+ tm.unregisterTelephonyCallback(mInternetTelephonyCallback);
+ }
mSubscriptionManager.removeOnSubscriptionsChangedListener(
mOnSubscriptionsChangedListener);
mAccessPointController.removeAccessPointCallback(this);
@@ -371,7 +396,10 @@
if (DEBUG) {
Log.d(TAG, "No Wi-Fi item.");
}
- if (!hasActiveSubId() || (!isVoiceStateInService() && !isDataStateInService())) {
+ boolean isActiveOnNonDds = getActiveAutoSwitchNonDdsSubId() != SubscriptionManager
+ .INVALID_SUBSCRIPTION_ID;
+ if (!hasActiveSubId() || (!isVoiceStateInService(mDefaultDataSubId)
+ && !isDataStateInService(mDefaultDataSubId) && !isActiveOnNonDds)) {
if (DEBUG) {
Log.d(TAG, "No carrier or service is out of service.");
}
@@ -412,7 +440,7 @@
return drawable;
}
- Drawable getSignalStrengthDrawable() {
+ Drawable getSignalStrengthDrawable(int subId) {
Drawable drawable = mContext.getDrawable(
R.drawable.ic_signal_strength_zero_bar_no_internet);
try {
@@ -424,9 +452,10 @@
}
boolean isCarrierNetworkActive = isCarrierNetworkActive();
- if (isDataStateInService() || isVoiceStateInService() || isCarrierNetworkActive) {
+ if (isDataStateInService(subId) || isVoiceStateInService(subId)
+ || isCarrierNetworkActive) {
AtomicReference<Drawable> shared = new AtomicReference<>();
- shared.set(getSignalStrengthDrawableWithLevel(isCarrierNetworkActive));
+ shared.set(getSignalStrengthDrawableWithLevel(isCarrierNetworkActive, subId));
drawable = shared.get();
}
@@ -447,24 +476,30 @@
*
* @return The Drawable which is a signal bar icon with level.
*/
- Drawable getSignalStrengthDrawableWithLevel(boolean isCarrierNetworkActive) {
- final SignalStrength strength = mTelephonyManager.getSignalStrength();
+ Drawable getSignalStrengthDrawableWithLevel(boolean isCarrierNetworkActive, int subId) {
+ TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager);
+ final SignalStrength strength = tm.getSignalStrength();
int level = (strength == null) ? 0 : strength.getLevel();
int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
if (isCarrierNetworkActive) {
level = getCarrierNetworkLevel();
numLevels = WifiEntry.WIFI_LEVEL_MAX + 1;
- } else if (mSubscriptionManager != null && shouldInflateSignalStrength(mDefaultDataSubId)) {
+ } else if (mSubscriptionManager != null && shouldInflateSignalStrength(subId)) {
level += 1;
numLevels += 1;
}
- return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON,
+ return getSignalStrengthIcon(subId, mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON,
!isMobileDataEnabled());
}
- Drawable getSignalStrengthIcon(Context context, int level, int numLevels,
+ Drawable getSignalStrengthIcon(int subId, Context context, int level, int numLevels,
int iconType, boolean cutOut) {
- mSignalDrawable.setLevel(SignalDrawable.getState(level, numLevels, cutOut));
+ boolean isForDds = subId == mDefaultDataSubId;
+ if (isForDds) {
+ mSignalDrawable.setLevel(SignalDrawable.getState(level, numLevels, cutOut));
+ } else {
+ mSecondarySignalDrawable.setLevel(SignalDrawable.getState(level, numLevels, cutOut));
+ }
// Make the network type drawable
final Drawable networkDrawable =
@@ -473,7 +508,8 @@
: context.getResources().getDrawable(iconType, context.getTheme());
// Overlay the two drawables
- final Drawable[] layers = {networkDrawable, mSignalDrawable};
+ final Drawable[] layers = {networkDrawable, isForDds
+ ? mSignalDrawable : mSecondarySignalDrawable};
final int iconSize =
context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size);
@@ -571,14 +607,39 @@
info -> info.uniqueName));
}
- CharSequence getMobileNetworkTitle() {
- return getUniqueSubscriptionDisplayName(mDefaultDataSubId, mContext);
+ /**
+ * @return the subId of the visible non-DDS if it's actively being used for data, otherwise
+ * return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ */
+ int getActiveAutoSwitchNonDdsSubId() {
+ if (!mFeatureFlags.isEnabled(Flags.QS_SECONDARY_DATA_SUB_INFO)) {
+ // sets the non-DDS to be not found to hide its visual
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+ SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(
+ SubscriptionManager.getActiveDataSubscriptionId());
+ if (subInfo != null && subInfo.getSubscriptionId() != mDefaultDataSubId
+ && !subInfo.isOpportunistic()) {
+ int subId = subInfo.getSubscriptionId();
+ if (mSubIdTelephonyManagerMap.get(subId) == null) {
+ TelephonyManager secondaryTm = mTelephonyManager.createForSubscriptionId(subId);
+ secondaryTm.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback);
+ mSubIdTelephonyManagerMap.put(subId, secondaryTm);
+ }
+ return subId;
+ }
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
}
- String getMobileNetworkSummary() {
+ CharSequence getMobileNetworkTitle(int subId) {
+ return getUniqueSubscriptionDisplayName(subId, mContext);
+ }
+
+ String getMobileNetworkSummary(int subId) {
String description = getNetworkTypeDescription(mContext, mConfig,
- mTelephonyDisplayInfo, mDefaultDataSubId);
- return getMobileSummary(mContext, description);
+ mTelephonyDisplayInfo, subId);
+ return getMobileSummary(mContext, description, subId);
}
/**
@@ -606,22 +667,28 @@
? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : "";
}
- private String getMobileSummary(Context context, String networkTypeDescription) {
+ private String getMobileSummary(Context context, String networkTypeDescription, int subId) {
if (!isMobileDataEnabled()) {
return context.getString(R.string.mobile_data_off_summary);
}
String summary = networkTypeDescription;
+ boolean isForDds = subId == mDefaultDataSubId;
+ int activeSubId = getActiveAutoSwitchNonDdsSubId();
+ boolean isOnNonDds = activeSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID;
// Set network description for the carrier network when connecting to the carrier network
// under the airplane mode ON.
if (activeNetworkIsCellular() || isCarrierNetworkActive()) {
summary = context.getString(R.string.preference_summary_default_combination,
- context.getString(R.string.mobile_data_connection_active),
+ context.getString(
+ isForDds // if nonDds is active, explains Dds status as poor connection
+ ? (isOnNonDds ? R.string.mobile_data_poor_connection
+ : R.string.mobile_data_connection_active)
+ : R.string.mobile_data_temp_connection_active),
networkTypeDescription);
- } else if (!isDataStateInService()) {
+ } else if (!isDataStateInService(subId)) {
summary = context.getString(R.string.mobile_data_no_connection);
}
-
return summary;
}
@@ -647,6 +714,26 @@
}
}
+ void launchMobileNetworkSettings(View view) {
+ final int subId = getActiveAutoSwitchNonDdsSubId();
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ Log.w(TAG, "launchMobileNetworkSettings fail, invalid subId:" + subId);
+ return;
+ }
+ startActivity(getSubSettingIntent(subId), view);
+ }
+
+ Intent getSubSettingIntent(int subId) {
+ final Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
+
+ final Bundle fragmentArgs = new Bundle();
+ // Special contract for Settings to highlight permission row
+ fragmentArgs.putString(SETTINGS_EXTRA_FRAGMENT_ARG_KEY, AUTO_DATA_SWITCH_SETTING_R_ID);
+ fragmentArgs.putInt(Settings.EXTRA_SUB_ID, subId);
+ intent.putExtra(SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
+ return intent;
+ }
+
void launchWifiScanningSetting(View view) {
final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -824,8 +911,20 @@
mWorkerHandler.post(() -> setMergedCarrierWifiEnabledIfNeed(subId, enabled));
}
- boolean isDataStateInService() {
- final ServiceState serviceState = mTelephonyManager.getServiceState();
+ void setAutoDataSwitchMobileDataPolicy(int subId, boolean enable) {
+ TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager);
+ if (tm == null) {
+ if (DEBUG) {
+ Log.d(TAG, "TelephonyManager is null, can not set mobile data.");
+ }
+ return;
+ }
+ tm.setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, enable);
+ }
+
+ boolean isDataStateInService(int subId) {
+ TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager);
+ final ServiceState serviceState = tm.getServiceState();
NetworkRegistrationInfo regInfo =
(serviceState == null) ? null : serviceState.getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS,
@@ -833,7 +932,7 @@
return (regInfo == null) ? false : regInfo.isRegistered();
}
- boolean isVoiceStateInService() {
+ boolean isVoiceStateInService(int subId) {
if (mTelephonyManager == null) {
if (DEBUG) {
Log.d(TAG, "TelephonyManager is null, can not detect voice state.");
@@ -841,7 +940,8 @@
return false;
}
- final ServiceState serviceState = mTelephonyManager.getServiceState();
+ TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager);
+ final ServiceState serviceState = tm.getServiceState();
return serviceState != null
&& serviceState.getState() == serviceState.STATE_IN_SERVICE;
}
@@ -1132,6 +1232,7 @@
if (SubscriptionManager.isUsableSubscriptionId(mDefaultDataSubId)) {
mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
+ mSubIdTelephonyManagerMap.put(mDefaultDataSubId, mTelephonyManager);
mTelephonyManager.registerTelephonyCallback(mHandler::post,
mInternetTelephonyCallback);
mCallback.onSubscriptionsChanged(mDefaultDataSubId);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index 8566ca3..796672d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -66,7 +66,8 @@
} else {
internetDialog = InternetDialog(
context, this, internetDialogController,
- canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler,
+ canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger,
+ dialogLaunchAnimator, handler,
executor, keyguardStateController
)
if (view != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 231e415..d524a35 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -20,6 +20,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
@@ -634,6 +635,11 @@
return true;
}
});
+
+ if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
+ mScreenshotView.badgeScreenshot(
+ mContext.getPackageManager().getUserBadgeForDensity(owner, 0));
+ }
mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);
if (DEBUG_WINDOW) {
Log.d(TAG, "setContentView: " + mScreenshotView);
@@ -1038,7 +1044,7 @@
private boolean isUserSetupComplete(UserHandle owner) {
return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
- .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+ .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 1b9cdd4..27331ae 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -74,7 +74,6 @@
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -122,15 +121,9 @@
private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
- private static final long SCREENSHOT_DISMISS_X_DURATION_MS = 350;
- private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 350;
- private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
- private static final float ROUNDED_CORNER_RADIUS = .25f;
private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
- private final Interpolator mAccelerateInterpolator = new AccelerateInterpolator();
-
private final Resources mResources;
private final Interpolator mFastOutSlowIn;
private final DisplayMetrics mDisplayMetrics;
@@ -145,6 +138,7 @@
private ImageView mScrollingScrim;
private DraggableConstraintLayout mScreenshotStatic;
private ImageView mScreenshotPreview;
+ private ImageView mScreenshotBadge;
private View mScreenshotPreviewBorder;
private ImageView mScrollablePreview;
private ImageView mScreenshotFlash;
@@ -355,6 +349,7 @@
mScreenshotPreviewBorder = requireNonNull(
findViewById(R.id.screenshot_preview_border));
mScreenshotPreview.setClipToOutline(true);
+ mScreenshotBadge = requireNonNull(findViewById(R.id.screenshot_badge));
mActionsContainerBackground = requireNonNull(findViewById(
R.id.actions_container_background));
@@ -595,8 +590,11 @@
ValueAnimator borderFadeIn = ValueAnimator.ofFloat(0, 1);
borderFadeIn.setDuration(100);
- borderFadeIn.addUpdateListener((animation) ->
- mScreenshotPreviewBorder.setAlpha(animation.getAnimatedFraction()));
+ borderFadeIn.addUpdateListener((animation) -> {
+ float borderAlpha = animation.getAnimatedFraction();
+ mScreenshotPreviewBorder.setAlpha(borderAlpha);
+ mScreenshotBadge.setAlpha(borderAlpha);
+ });
if (showFlash) {
dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
@@ -763,6 +761,11 @@
return animator;
}
+ void badgeScreenshot(Drawable badge) {
+ mScreenshotBadge.setImageDrawable(badge);
+ mScreenshotBadge.setVisibility(badge != null ? View.VISIBLE : View.GONE);
+ }
+
void setChipIntents(ScreenshotController.SavedImageData imageData) {
mShareChip.setOnClickListener(v -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
@@ -1027,6 +1030,9 @@
mScreenshotPreview.setVisibility(View.INVISIBLE);
mScreenshotPreview.setAlpha(1f);
mScreenshotPreviewBorder.setAlpha(0);
+ mScreenshotBadge.setAlpha(0f);
+ mScreenshotBadge.setVisibility(View.GONE);
+ mScreenshotBadge.setImageDrawable(null);
mPendingSharedTransition = false;
mActionsContainerBackground.setVisibility(View.GONE);
mActionsContainer.setVisibility(View.GONE);
@@ -1082,6 +1088,7 @@
mActionsContainerBackground.setAlpha(alpha);
mActionsContainer.setAlpha(alpha);
mScreenshotPreviewBorder.setAlpha(alpha);
+ mScreenshotBadge.setAlpha(alpha);
});
alphaAnim.setDuration(600);
return alphaAnim;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 8de0365..277ad8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1374,13 +1374,8 @@
if (bubbleButton == null || actionContainer == null) {
return;
}
- boolean isPersonWithShortcut =
- mPeopleIdentifier.getPeopleNotificationType(entry)
- >= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
- boolean showButton = BubblesManager.areBubblesEnabled(mContext, entry.getSbn().getUser())
- && isPersonWithShortcut
- && entry.getBubbleMetadata() != null;
- if (showButton) {
+
+ if (shouldShowBubbleButton(entry)) {
// explicitly resolve drawable resource using SystemUI's theme
Drawable d = mContext.getDrawable(entry.isBubble()
? R.drawable.bubble_ic_stop_bubble
@@ -1410,6 +1405,16 @@
}
}
+ @VisibleForTesting
+ boolean shouldShowBubbleButton(NotificationEntry entry) {
+ boolean isPersonWithShortcut =
+ mPeopleIdentifier.getPeopleNotificationType(entry)
+ >= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
+ return BubblesManager.areBubblesEnabled(mContext, entry.getSbn().getUser())
+ && isPersonWithShortcut
+ && entry.getBubbleMetadata() != null;
+ }
+
private void applySnoozeAction(View layout) {
if (layout == null || mContainingNotification == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 29642be..43bc99f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2960,7 +2960,10 @@
// * When phone is unlocked: we still don't want to execute hiding of the keyguard
// as the animation could prepare 'fake AOD' interface (without actually
// transitioning to keyguard state) and this might reset the view states
- if (!mScreenOffAnimationController.isKeyguardHideDelayed()) {
+ if (!mScreenOffAnimationController.isKeyguardHideDelayed()
+ // If we're animating occluded, there's an activity launching over the keyguard
+ // UI. Wait to hide it until after the animation concludes.
+ && !mKeyguardViewMediator.isOccludeAnimationPlaying()) {
return hideKeyguardImpl(forceStateChange);
}
}
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 8490768..cf3a48c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -53,6 +53,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -204,6 +205,7 @@
private final ScreenOffAnimationController mScreenOffAnimationController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private KeyguardViewMediator mKeyguardViewMediator;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -273,7 +275,8 @@
@Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ KeyguardViewMediator keyguardViewMediator) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
@@ -312,6 +315,8 @@
}
});
mColors = new GradientColors();
+
+ mKeyguardViewMediator = keyguardViewMediator;
}
/**
@@ -807,6 +812,13 @@
mBehindTint,
interpolatedFraction);
}
+
+ // If we're unlocked but still playing the occlude animation, remain at the keyguard
+ // alpha temporarily.
+ if (mKeyguardViewMediator.isOccludeAnimationPlaying()
+ || mState.mLaunchingAffordanceWithPreview) {
+ mNotificationsAlpha = KEYGUARD_SCRIM_ALPHA;
+ }
} else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) {
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 2aaa085..fcd1b8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -18,10 +18,14 @@
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepositoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryImpl
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepositoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyImpl
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
@@ -41,10 +45,16 @@
abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
@Binds
- abstract fun mobileSubscriptionRepository(
- impl: MobileSubscriptionRepositoryImpl
- ): MobileSubscriptionRepository
+ abstract fun mobileConnectionsRepository(
+ impl: MobileConnectionsRepositoryImpl
+ ): MobileConnectionsRepository
@Binds
abstract fun userSetupRepository(impl: UserSetupRepositoryImpl): UserSetupRepository
+
+ @Binds
+ abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
+
+ @Binds
+ abstract fun mobileIconsInteractor(impl: MobileIconsInteractorImpl): MobileIconsInteractor
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt
index 46ccf32c..eaba0e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt
@@ -27,6 +27,7 @@
import android.telephony.TelephonyCallback.SignalStrengthsListener
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
/**
* Data class containing all of the relevant information for a particular line of service, known as
@@ -57,6 +58,11 @@
/** From [CarrierNetworkListener.onCarrierNetworkChange] */
val carrierNetworkChangeActive: Boolean? = null,
- /** From [DisplayInfoListener.onDisplayInfoChanged] */
- val displayInfo: TelephonyDisplayInfo? = null
+ /**
+ * From [DisplayInfoListener.onDisplayInfoChanged].
+ *
+ * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
+ * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
+ */
+ val resolvedNetworkType: ResolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN),
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
new file mode 100644
index 0000000..f385806
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.model
+
+import android.telephony.Annotation.NetworkType
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+
+/**
+ * A SysUI type to represent the [NetworkType] that we pull out of [TelephonyDisplayInfo]. Depending
+ * on whether or not the display info contains an override type, we may have to call different
+ * methods on [MobileMappingsProxy] to generate an icon lookup key.
+ */
+sealed interface ResolvedNetworkType {
+ @NetworkType val type: Int
+}
+
+data class DefaultNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType
+
+data class OverrideNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
new file mode 100644
index 0000000..45284cf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.CellSignalStrength
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
+import android.telephony.TelephonyManager
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import java.lang.IllegalStateException
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Every mobile line of service can be identified via a [SubscriptionInfo] object. We set up a
+ * repository for each individual, tracked subscription via [MobileConnectionsRepository], and this
+ * repository is responsible for setting up a [TelephonyManager] object tied to its subscriptionId
+ *
+ * There should only ever be one [MobileConnectionRepository] per subscription, since
+ * [TelephonyManager] limits the number of callbacks that can be registered per process.
+ *
+ * This repository should have all of the relevant information for a single line of service, which
+ * eventually becomes a single icon in the status bar.
+ */
+interface MobileConnectionRepository {
+ /**
+ * A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
+ * listener + model.
+ */
+ val subscriptionModelFlow: Flow<MobileSubscriptionModel>
+}
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+class MobileConnectionRepositoryImpl(
+ private val subId: Int,
+ telephonyManager: TelephonyManager,
+ bgDispatcher: CoroutineDispatcher,
+ logger: ConnectivityPipelineLogger,
+ scope: CoroutineScope,
+) : MobileConnectionRepository {
+ init {
+ if (telephonyManager.subscriptionId != subId) {
+ throw IllegalStateException(
+ "TelephonyManager should be created with subId($subId). " +
+ "Found ${telephonyManager.subscriptionId} instead."
+ )
+ }
+ }
+
+ override val subscriptionModelFlow: StateFlow<MobileSubscriptionModel> = run {
+ var state = MobileSubscriptionModel()
+ conflatedCallbackFlow {
+ // TODO (b/240569788): log all of these into the connectivity logger
+ val callback =
+ object :
+ TelephonyCallback(),
+ TelephonyCallback.ServiceStateListener,
+ TelephonyCallback.SignalStrengthsListener,
+ TelephonyCallback.DataConnectionStateListener,
+ TelephonyCallback.DataActivityListener,
+ TelephonyCallback.CarrierNetworkListener,
+ TelephonyCallback.DisplayInfoListener {
+ override fun onServiceStateChanged(serviceState: ServiceState) {
+ state = state.copy(isEmergencyOnly = serviceState.isEmergencyOnly)
+ trySend(state)
+ }
+
+ override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
+ val cdmaLevel =
+ signalStrength
+ .getCellSignalStrengths(CellSignalStrengthCdma::class.java)
+ .let { strengths ->
+ if (!strengths.isEmpty()) {
+ strengths[0].level
+ } else {
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+ }
+ }
+
+ val primaryLevel = signalStrength.level
+
+ state =
+ state.copy(
+ cdmaLevel = cdmaLevel,
+ primaryLevel = primaryLevel,
+ isGsm = signalStrength.isGsm,
+ )
+ trySend(state)
+ }
+
+ override fun onDataConnectionStateChanged(
+ dataState: Int,
+ networkType: Int
+ ) {
+ state = state.copy(dataConnectionState = dataState)
+ trySend(state)
+ }
+
+ override fun onDataActivity(direction: Int) {
+ state = state.copy(dataActivityDirection = direction)
+ trySend(state)
+ }
+
+ override fun onCarrierNetworkChange(active: Boolean) {
+ state = state.copy(carrierNetworkChangeActive = active)
+ trySend(state)
+ }
+
+ override fun onDisplayInfoChanged(
+ telephonyDisplayInfo: TelephonyDisplayInfo
+ ) {
+ val networkType =
+ if (
+ telephonyDisplayInfo.overrideNetworkType ==
+ OVERRIDE_NETWORK_TYPE_NONE
+ ) {
+ DefaultNetworkType(telephonyDisplayInfo.networkType)
+ } else {
+ OverrideNetworkType(telephonyDisplayInfo.overrideNetworkType)
+ }
+ state = state.copy(resolvedNetworkType = networkType)
+ trySend(state)
+ }
+ }
+ telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+ awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+ }
+ .onEach { logger.logOutputChange("mobileSubscriptionModel", it.toString()) }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), state)
+ }
+
+ class Factory
+ @Inject
+ constructor(
+ private val telephonyManager: TelephonyManager,
+ private val logger: ConnectivityPipelineLogger,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ @Application private val scope: CoroutineScope,
+ ) {
+ fun build(subId: Int): MobileConnectionRepository {
+ return MobileConnectionRepositoryImpl(
+ subId,
+ telephonyManager.createForSubscriptionId(subId),
+ bgDispatcher,
+ logger,
+ scope,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
new file mode 100644
index 0000000..0e2428a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.content.Context
+import android.content.IntentFilter
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyManager
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.broadcast.BroadcastDispatcher
+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.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/**
+ * Repo for monitoring the complete active subscription info list, to be consumed and filtered based
+ * on various policy
+ */
+interface MobileConnectionsRepository {
+ /** Observable list of current mobile subscriptions */
+ val subscriptionsFlow: Flow<List<SubscriptionInfo>>
+
+ /** Observable for the subscriptionId of the current mobile data connection */
+ val activeMobileDataSubscriptionId: Flow<Int>
+
+ /** Observable for [MobileMappings.Config] tracking the defaults */
+ val defaultDataSubRatConfig: StateFlow<Config>
+
+ /** Get or create a repository for the line of service for the given subscription ID */
+ fun getRepoForSubId(subId: Int): MobileConnectionRepository
+}
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class MobileConnectionsRepositoryImpl
+@Inject
+constructor(
+ private val subscriptionManager: SubscriptionManager,
+ private val telephonyManager: TelephonyManager,
+ private val logger: ConnectivityPipelineLogger,
+ broadcastDispatcher: BroadcastDispatcher,
+ private val context: Context,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ @Application private val scope: CoroutineScope,
+ private val mobileConnectionRepositoryFactory: MobileConnectionRepositoryImpl.Factory
+) : MobileConnectionsRepository {
+ private val subIdRepositoryCache: MutableMap<Int, MobileConnectionRepository> = mutableMapOf()
+
+ /**
+ * State flow that emits the set of mobile data subscriptions, each represented by its own
+ * [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each
+ * info object, but for now we keep track of the infos themselves.
+ */
+ override val subscriptionsFlow: StateFlow<List<SubscriptionInfo>> =
+ conflatedCallbackFlow {
+ val callback =
+ object : SubscriptionManager.OnSubscriptionsChangedListener() {
+ override fun onSubscriptionsChanged() {
+ trySend(Unit)
+ }
+ }
+
+ subscriptionManager.addOnSubscriptionsChangedListener(
+ bgDispatcher.asExecutor(),
+ callback,
+ )
+
+ awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
+ }
+ .mapLatest { fetchSubscriptionsList() }
+ .onEach { infos -> dropUnusedReposFromCache(infos) }
+ .stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
+
+ /** StateFlow that keeps track of the current active mobile data subscription */
+ override val activeMobileDataSubscriptionId: StateFlow<Int> =
+ conflatedCallbackFlow {
+ val callback =
+ object : TelephonyCallback(), ActiveDataSubscriptionIdListener {
+ override fun onActiveDataSubscriptionIdChanged(subId: Int) {
+ trySend(subId)
+ }
+ }
+
+ telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+ awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+ }
+ .stateIn(
+ scope,
+ started = SharingStarted.WhileSubscribed(),
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ )
+
+ private val defaultDataSubChangedEvent =
+ broadcastDispatcher.broadcastFlow(
+ IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ )
+
+ private val carrierConfigChangedEvent =
+ broadcastDispatcher.broadcastFlow(
+ IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
+ )
+
+ /**
+ * [Config] is an object that tracks relevant configuration flags for a given subscription ID.
+ * In the case of [MobileMappings], it's hard-coded to check the default data subscription's
+ * config, so this will apply to every icon that we care about.
+ *
+ * Relevant bits in the config are things like
+ * [CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL]
+ *
+ * This flow will produce whenever the default data subscription or the carrier config changes.
+ */
+ override val defaultDataSubRatConfig: StateFlow<Config> =
+ combine(defaultDataSubChangedEvent, carrierConfigChangedEvent) { _, _ ->
+ Config.readConfig(context)
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ initialValue = Config.readConfig(context)
+ )
+
+ override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
+ if (!isValidSubId(subId)) {
+ throw IllegalArgumentException(
+ "subscriptionId $subId is not in the list of valid subscriptions"
+ )
+ }
+
+ return subIdRepositoryCache[subId]
+ ?: createRepositoryForSubId(subId).also { subIdRepositoryCache[subId] = it }
+ }
+
+ private fun isValidSubId(subId: Int): Boolean {
+ subscriptionsFlow.value.forEach {
+ if (it.subscriptionId == subId) {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ @VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
+
+ private fun createRepositoryForSubId(subId: Int): MobileConnectionRepository {
+ return mobileConnectionRepositoryFactory.build(subId)
+ }
+
+ private fun dropUnusedReposFromCache(newInfos: List<SubscriptionInfo>) {
+ // Remove any connection repository from the cache that isn't in the new set of IDs. They
+ // will get garbage collected once their subscribers go away
+ val currentValidSubscriptionIds = newInfos.map { it.subscriptionId }
+
+ subIdRepositoryCache.keys.forEach {
+ if (!currentValidSubscriptionIds.contains(it)) {
+ subIdRepositoryCache.remove(it)
+ }
+ }
+ }
+
+ private suspend fun fetchSubscriptionsList(): List<SubscriptionInfo> =
+ withContext(bgDispatcher) { subscriptionManager.completeActiveSubscriptionInfoList }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepository.kt
deleted file mode 100644
index 36de2a2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepository.kt
+++ /dev/null
@@ -1,210 +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 com.android.systemui.statusbar.pipeline.mobile.data.repository
-
-import android.telephony.CellSignalStrength
-import android.telephony.CellSignalStrengthCdma
-import android.telephony.ServiceState
-import android.telephony.SignalStrength
-import android.telephony.SubscriptionInfo
-import android.telephony.SubscriptionManager
-import android.telephony.TelephonyCallback
-import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
-import android.telephony.TelephonyCallback.CarrierNetworkListener
-import android.telephony.TelephonyCallback.DataActivityListener
-import android.telephony.TelephonyCallback.DataConnectionStateListener
-import android.telephony.TelephonyCallback.DisplayInfoListener
-import android.telephony.TelephonyCallback.ServiceStateListener
-import android.telephony.TelephonyCallback.SignalStrengthsListener
-import android.telephony.TelephonyDisplayInfo
-import android.telephony.TelephonyManager
-import androidx.annotation.VisibleForTesting
-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.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.asExecutor
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.withContext
-
-/**
- * Repo for monitoring the complete active subscription info list, to be consumed and filtered based
- * on various policy
- */
-interface MobileSubscriptionRepository {
- /** Observable list of current mobile subscriptions */
- val subscriptionsFlow: Flow<List<SubscriptionInfo>>
-
- /** Observable for the subscriptionId of the current mobile data connection */
- val activeMobileDataSubscriptionId: Flow<Int>
-
- /** Get or create an observable for the given subscription ID */
- fun getFlowForSubId(subId: Int): Flow<MobileSubscriptionModel>
-}
-
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
-@SysUISingleton
-class MobileSubscriptionRepositoryImpl
-@Inject
-constructor(
- private val subscriptionManager: SubscriptionManager,
- private val telephonyManager: TelephonyManager,
- @Background private val bgDispatcher: CoroutineDispatcher,
- @Application private val scope: CoroutineScope,
-) : MobileSubscriptionRepository {
- private val subIdFlowCache: MutableMap<Int, StateFlow<MobileSubscriptionModel>> = mutableMapOf()
-
- /**
- * State flow that emits the set of mobile data subscriptions, each represented by its own
- * [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each
- * info object, but for now we keep track of the infos themselves.
- */
- override val subscriptionsFlow: StateFlow<List<SubscriptionInfo>> =
- conflatedCallbackFlow {
- val callback =
- object : SubscriptionManager.OnSubscriptionsChangedListener() {
- override fun onSubscriptionsChanged() {
- trySend(Unit)
- }
- }
-
- subscriptionManager.addOnSubscriptionsChangedListener(
- bgDispatcher.asExecutor(),
- callback,
- )
-
- awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
- }
- .mapLatest { fetchSubscriptionsList() }
- .stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
-
- /** StateFlow that keeps track of the current active mobile data subscription */
- override val activeMobileDataSubscriptionId: StateFlow<Int> =
- conflatedCallbackFlow {
- val callback =
- object : TelephonyCallback(), ActiveDataSubscriptionIdListener {
- override fun onActiveDataSubscriptionIdChanged(subId: Int) {
- trySend(subId)
- }
- }
-
- telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
- awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
- }
- .stateIn(
- scope,
- started = SharingStarted.WhileSubscribed(),
- SubscriptionManager.INVALID_SUBSCRIPTION_ID
- )
-
- /**
- * Each mobile subscription needs its own flow, which comes from registering listeners on the
- * system. Use this method to create those flows and cache them for reuse
- */
- override fun getFlowForSubId(subId: Int): StateFlow<MobileSubscriptionModel> {
- return subIdFlowCache[subId]
- ?: createFlowForSubId(subId).also { subIdFlowCache[subId] = it }
- }
-
- @VisibleForTesting fun getSubIdFlowCache() = subIdFlowCache
-
- private fun createFlowForSubId(subId: Int): StateFlow<MobileSubscriptionModel> = run {
- var state = MobileSubscriptionModel()
- conflatedCallbackFlow {
- val phony = telephonyManager.createForSubscriptionId(subId)
- // TODO (b/240569788): log all of these into the connectivity logger
- val callback =
- object :
- TelephonyCallback(),
- ServiceStateListener,
- SignalStrengthsListener,
- DataConnectionStateListener,
- DataActivityListener,
- CarrierNetworkListener,
- DisplayInfoListener {
- override fun onServiceStateChanged(serviceState: ServiceState) {
- state = state.copy(isEmergencyOnly = serviceState.isEmergencyOnly)
- trySend(state)
- }
- override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
- val cdmaLevel =
- signalStrength
- .getCellSignalStrengths(CellSignalStrengthCdma::class.java)
- .let { strengths ->
- if (!strengths.isEmpty()) {
- strengths[0].level
- } else {
- CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
- }
- }
-
- val primaryLevel = signalStrength.level
-
- state =
- state.copy(
- cdmaLevel = cdmaLevel,
- primaryLevel = primaryLevel,
- isGsm = signalStrength.isGsm,
- )
- trySend(state)
- }
- override fun onDataConnectionStateChanged(
- dataState: Int,
- networkType: Int
- ) {
- state = state.copy(dataConnectionState = dataState)
- trySend(state)
- }
- override fun onDataActivity(direction: Int) {
- state = state.copy(dataActivityDirection = direction)
- trySend(state)
- }
- override fun onCarrierNetworkChange(active: Boolean) {
- state = state.copy(carrierNetworkChangeActive = active)
- trySend(state)
- }
- override fun onDisplayInfoChanged(
- telephonyDisplayInfo: TelephonyDisplayInfo
- ) {
- state = state.copy(displayInfo = telephonyDisplayInfo)
- trySend(state)
- }
- }
- phony.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
- awaitClose {
- phony.unregisterTelephonyCallback(callback)
- // Release the cached flow
- subIdFlowCache.remove(subId)
- }
- }
- .stateIn(scope, SharingStarted.WhileSubscribed(), state)
- }
-
- private suspend fun fetchSubscriptionsList(): List<SubscriptionInfo> =
- withContext(bgDispatcher) { subscriptionManager.completeActiveSubscriptionInfoList }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 40fe0f3..15f4acc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -17,32 +17,58 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.CarrierConfigManager
-import com.android.settingslib.SignalIcon
-import com.android.settingslib.mobile.TelephonyIcons
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
interface MobileIconInteractor {
- /** Identifier for RAT type indicator */
- val iconGroup: Flow<SignalIcon.MobileIconGroup>
+ /** Observable for RAT type (network type) indicator */
+ val networkTypeIconGroup: Flow<MobileIconGroup>
+
/** True if this line of service is emergency-only */
val isEmergencyOnly: Flow<Boolean>
+
/** Int describing the connection strength. 0-4 OR 1-5. See [numberOfLevels] */
val level: Flow<Int>
+
/** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
val numberOfLevels: Flow<Int>
+
/** True when we want to draw an icon that makes room for the exclamation mark */
val cutOut: Flow<Boolean>
}
/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
class MobileIconInteractorImpl(
- mobileStatusInfo: Flow<MobileSubscriptionModel>,
+ defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>,
+ defaultMobileIconGroup: Flow<MobileIconGroup>,
+ mobileMappingsProxy: MobileMappingsProxy,
+ connectionRepository: MobileConnectionRepository,
) : MobileIconInteractor {
- override val iconGroup: Flow<SignalIcon.MobileIconGroup> = flowOf(TelephonyIcons.THREE_G)
+ private val mobileStatusInfo = connectionRepository.subscriptionModelFlow
+
+ /** Observable for the current RAT indicator icon ([MobileIconGroup]) */
+ override val networkTypeIconGroup: Flow<MobileIconGroup> =
+ combine(
+ mobileStatusInfo,
+ defaultMobileIconMapping,
+ defaultMobileIconGroup,
+ ) { info, mapping, defaultGroup ->
+ val lookupKey =
+ when (val resolved = info.resolvedNetworkType) {
+ is DefaultNetworkType -> mobileMappingsProxy.toIconKey(resolved.type)
+ is OverrideNetworkType -> mobileMappingsProxy.toIconKeyOverride(resolved.type)
+ }
+ mapping[lookupKey] ?: defaultGroup
+ }
+
override val isEmergencyOnly: Flow<Boolean> = mobileStatusInfo.map { it.isEmergencyOnly }
override val level: Flow<Int> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 8e67e19..cd411a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -19,29 +19,51 @@
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepository
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
/**
- * Business layer logic for mobile subscription icons
+ * Business layer logic for the set of mobile subscription icons.
*
- * Mobile indicators represent the UI for the (potentially filtered) list of [SubscriptionInfo]s
- * that the system knows about. They obey policy that depends on OEM, carrier, and locale configs
+ * This interactor represents known set of mobile subscriptions (represented by [SubscriptionInfo]).
+ * The list of subscriptions is filtered based on the opportunistic flags on the infos.
+ *
+ * It provides the default mapping between the telephony display info and the icon group that
+ * represents each RAT (LTE, 3G, etc.), as well as can produce an interactor for each individual
+ * icon
*/
+interface MobileIconsInteractor {
+ val filteredSubscriptions: Flow<List<SubscriptionInfo>>
+ val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>
+ val defaultMobileIconGroup: Flow<MobileIconGroup>
+ val isUserSetup: Flow<Boolean>
+ fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
+}
+
@SysUISingleton
-class MobileIconsInteractor
+class MobileIconsInteractorImpl
@Inject
constructor(
- private val mobileSubscriptionRepo: MobileSubscriptionRepository,
+ private val mobileSubscriptionRepo: MobileConnectionsRepository,
private val carrierConfigTracker: CarrierConfigTracker,
+ private val mobileMappingsProxy: MobileMappingsProxy,
userSetupRepo: UserSetupRepository,
-) {
+ @Application private val scope: CoroutineScope,
+) : MobileIconsInteractor {
private val activeMobileDataSubscriptionId =
mobileSubscriptionRepo.activeMobileDataSubscriptionId
@@ -61,7 +83,7 @@
* [CarrierConfigManager.KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN],
* and by checking which subscription is opportunistic, or which one is active.
*/
- val filteredSubscriptions: Flow<List<SubscriptionInfo>> =
+ override val filteredSubscriptions: Flow<List<SubscriptionInfo>> =
combine(unfilteredSubscriptions, activeMobileDataSubscriptionId) { unfilteredSubs, activeId
->
// Based on the old logic,
@@ -92,15 +114,29 @@
}
}
- val isUserSetup: Flow<Boolean> = userSetupRepo.isUserSetupFlow
+ /**
+ * Mapping from network type to [MobileIconGroup] using the config generated for the default
+ * subscription Id. This mapping is the same for every subscription.
+ */
+ override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> =
+ mobileSubscriptionRepo.defaultDataSubRatConfig
+ .map { mobileMappingsProxy.mapIconSets(it) }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
+
+ /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
+ override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
+ mobileSubscriptionRepo.defaultDataSubRatConfig
+ .map { mobileMappingsProxy.getDefaultIcons(it) }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G)
+
+ override val isUserSetup: Flow<Boolean> = userSetupRepo.isUserSetupFlow
/** Vends out new [MobileIconInteractor] for a particular subId */
- fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
- MobileIconInteractorImpl(mobileSubscriptionFlowForSubId(subId))
-
- /**
- * Create a new flow for a given subscription ID, which usually maps 1:1 with mobile connections
- */
- private fun mobileSubscriptionFlowForSubId(subId: Int): Flow<MobileSubscriptionModel> =
- mobileSubscriptionRepo.getFlowForSubId(subId)
+ override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+ MobileIconInteractorImpl(
+ defaultMobileIconMapping,
+ defaultMobileIconGroup,
+ mobileMappingsProxy,
+ mobileSubscriptionRepo.getRepoForSubId(subId),
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 1405b05..67ea139 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.pipeline.mobile.ui.binder
import android.content.res.ColorStateList
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.view.isVisible
@@ -24,6 +26,7 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.settingslib.graph.SignalDrawable
import com.android.systemui.R
+import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
import kotlinx.coroutines.flow.collect
@@ -37,6 +40,7 @@
view: ViewGroup,
viewModel: MobileIconViewModel,
) {
+ val networkTypeView = view.requireViewById<ImageView>(R.id.mobile_type)
val iconView = view.requireViewById<ImageView>(R.id.mobile_signal)
val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
@@ -52,10 +56,20 @@
}
}
+ // Set the network type icon
+ launch {
+ viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
+ dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
+ networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
+ }
+ }
+
// Set the tint
launch {
viewModel.tint.collect { tint ->
- iconView.imageTintList = ColorStateList.valueOf(tint)
+ val tintList = ColorStateList.valueOf(tint)
+ iconView.imageTintList = tintList
+ networkTypeView.imageTintList = tintList
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index cfabeba..cc8f6dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -18,6 +18,8 @@
import android.graphics.Color
import com.android.settingslib.graph.SignalDrawable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
@@ -26,6 +28,7 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
/**
* View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
@@ -54,5 +57,15 @@
.distinctUntilChanged()
.logOutputChange(logger, "iconId($subscriptionId)")
+ /** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
+ var networkTypeIcon: Flow<Icon?> =
+ iconInteractor.networkTypeIconGroup.map {
+ val desc =
+ if (it.dataContentDescription != 0)
+ ContentDescription.Resource(it.dataContentDescription)
+ else null
+ Icon.Resource(it.dataType, desc)
+ }
+
var tint: Flow<Int> = flowOf(Color.CYAN)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/util/MobileMappings.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/util/MobileMappings.kt
new file mode 100644
index 0000000..60bd038
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/util/MobileMappings.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.util
+
+import android.telephony.Annotation.NetworkType
+import android.telephony.TelephonyDisplayInfo
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.MobileMappings.Config
+import javax.inject.Inject
+
+/**
+ * [MobileMappings] owns the logic on creating the map from [TelephonyDisplayInfo] to
+ * [MobileIconGroup]. It creates that hash map and also manages the creation of lookup keys. This
+ * interface allows us to proxy those calls to the static java methods in SettingsLib and also fake
+ * them out in tests
+ */
+interface MobileMappingsProxy {
+ fun mapIconSets(config: Config): Map<String, MobileIconGroup>
+ fun getDefaultIcons(config: Config): MobileIconGroup
+ fun toIconKey(@NetworkType networkType: Int): String
+ fun toIconKeyOverride(@NetworkType networkType: Int): String
+}
+
+/** Injectable wrapper class for [MobileMappings] */
+class MobileMappingsProxyImpl @Inject constructor() : MobileMappingsProxy {
+ override fun mapIconSets(config: Config): Map<String, MobileIconGroup> =
+ MobileMappings.mapIconSets(config)
+
+ override fun getDefaultIcons(config: Config): MobileIconGroup =
+ MobileMappings.getDefaultIcons(config)
+
+ override fun toIconKey(@NetworkType networkType: Int): String =
+ MobileMappings.toIconKey(networkType)
+
+ override fun toIconKeyOverride(networkType: Int): String =
+ MobileMappings.toDisplayIconKey(networkType)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
index 28a9b97..cf4106c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
@@ -61,7 +61,7 @@
* animation to and from the parent dialog.
*/
@JvmOverloads
- fun onUserListItemClicked(
+ open fun onUserListItemClicked(
record: UserRecord,
dialogShower: DialogShower? = null,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index cd7bd2d..b8930a4 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -204,5 +204,4 @@
}
}
-const val SENDER_TAG = "MediaTapToTransferSender"
private const val ANIMATION_DURATION = 500L
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 627d738..61c7bb5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -44,7 +44,6 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
@@ -105,8 +104,6 @@
private FrameLayout mLargeClockFrame;
@Mock
private SecureSettings mSecureSettings;
- @Mock
- private FeatureFlags mFeatureFlags;
private final View mFakeSmartspaceView = new View(mContext);
@@ -143,8 +140,7 @@
mSecureSettings,
mExecutor,
mDumpManager,
- mClockEventController,
- mFeatureFlags
+ mClockEventController
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index f2ae7a1..d1107c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -54,6 +54,7 @@
import org.mockito.Mockito.anyLong
import org.mockito.Mockito.eq
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@@ -125,6 +126,21 @@
}
@Test
+ fun testDismissBeforeIntroEnd() {
+ val container = initializeFingerprintContainer()
+ waitForIdleSync()
+
+ // STATE_ANIMATING_IN = 1
+ container?.mContainerState = 1
+
+ container.dismissWithoutCallback(false)
+
+ // the first time is triggered by initializeFingerprintContainer()
+ // the second time was triggered by dismissWithoutCallback()
+ verify(callback, times(2)).onDialogAnimatedIn(authContainer?.requestId ?: 0L)
+ }
+
+ @Test
fun testDismissesOnFocusLoss() {
val container = initializeFingerprintContainer()
waitForIdleSync()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 4c986bf..2c3ddd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -60,6 +60,7 @@
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -112,6 +113,8 @@
private FalsingCollectorFake mFalsingCollector;
+ private @Mock CentralSurfaces mCentralSurfaces;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -258,6 +261,26 @@
verify(mKeyguardStateController).notifyKeyguardGoingAway(false);
}
+ @Test
+ public void testUpdateIsKeyguardAfterOccludeAnimationEnds() {
+ mViewMediator.mOccludeAnimationController.onLaunchAnimationEnd(
+ false /* isExpandingFullyAbove */);
+
+ // Since the updateIsKeyguard call is delayed during the animation, ensure it's called once
+ // it ends.
+ verify(mCentralSurfaces).updateIsKeyguard();
+ }
+
+ @Test
+ public void testUpdateIsKeyguardAfterOccludeAnimationIsCancelled() {
+ mViewMediator.mOccludeAnimationController.onLaunchAnimationCancelled(
+ null /* newKeyguardOccludedState */);
+
+ // Since the updateIsKeyguard call is delayed during the animation, ensure it's called if
+ // it's cancelled.
+ verify(mCentralSurfaces).updateIsKeyguard();
+ }
+
private void createAndStartViewMediator() {
mViewMediator = new KeyguardViewMediator(
mContext,
@@ -287,5 +310,7 @@
mNotificationShadeWindowControllerLazy,
() -> mActivityLaunchAnimator);
mViewMediator.start();
+
+ mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index bc27bbc..3131f60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.qs.QSUserSwitcherEvent
+import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.user.data.source.UserRecord
import org.junit.Assert.assertEquals
@@ -41,20 +42,27 @@
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class UserDetailViewAdapterTest : SysuiTestCase() {
- @Mock private lateinit var mUserSwitcherController: UserSwitcherController
- @Mock private lateinit var mParent: ViewGroup
- @Mock private lateinit var mUserDetailItemView: UserDetailItemView
- @Mock private lateinit var mOtherView: View
- @Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
- @Mock private lateinit var mLayoutInflater: LayoutInflater
+ @Mock
+ private lateinit var mUserSwitcherController: UserSwitcherController
+ @Mock
+ private lateinit var mParent: ViewGroup
+ @Mock
+ private lateinit var mUserDetailItemView: UserDetailItemView
+ @Mock
+ private lateinit var mOtherView: View
+ @Mock
+ private lateinit var mInflatedUserDetailItemView: UserDetailItemView
+ @Mock
+ private lateinit var mLayoutInflater: LayoutInflater
private var falsingManagerFake: FalsingManagerFake = FalsingManagerFake()
private lateinit var adapter: UserDetailView.Adapter
private lateinit var uiEventLogger: UiEventLoggerFake
@@ -67,10 +75,12 @@
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater)
`when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
- .thenReturn(mInflatedUserDetailItemView)
+ .thenReturn(mInflatedUserDetailItemView)
`when`(mParent.context).thenReturn(mContext)
- adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger,
- falsingManagerFake)
+ adapter = UserDetailView.Adapter(
+ mContext, mUserSwitcherController, uiEventLogger,
+ falsingManagerFake
+ )
mPicture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user))
}
@@ -145,6 +155,15 @@
assertNull(adapter.users.find { it.isManageUsers })
}
+ @Test
+ fun clickDismissDialog() {
+ val shower: UserSwitchDialogController.DialogShower =
+ mock(UserSwitchDialogController.DialogShower::class.java)
+ adapter.injectDialogShower(shower)
+ adapter.onUserListItemClicked(createUserRecord(current = true, guest = false), shower)
+ verify(shower).dismiss()
+ }
+
private fun createUserRecord(current: Boolean, guest: Boolean) =
UserRecord(
UserInfo(0 /* id */, "name", 0 /* flags */),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index d703705..2ef7312 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -5,6 +5,7 @@
import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GREAT;
import static android.telephony.SignalStrength.SIGNAL_STRENGTH_POOR;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_VERTICAL_WEIGHT;
import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX;
@@ -13,6 +14,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -38,6 +40,7 @@
import android.os.Handler;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
@@ -57,6 +60,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.UnreleasedFlag;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -70,12 +75,15 @@
import com.android.wifitrackerlib.MergedCarrierEntry;
import com.android.wifitrackerlib.WifiEntry;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.List;
@@ -86,6 +94,9 @@
public class InternetDialogControllerTest extends SysuiTestCase {
private static final int SUB_ID = 1;
+ private static final int SUB_ID2 = 2;
+
+ private MockitoSession mStaticMockSession;
//SystemUIToast
private static final int GRAVITY_FLAGS = Gravity.FILL_HORIZONTAL | Gravity.FILL_VERTICAL;
@@ -158,6 +169,8 @@
private WifiStateWorker mWifiStateWorker;
@Mock
private SignalStrength mSignalStrength;
+ @Mock
+ private FeatureFlags mFlags;
private TestableResources mTestableResources;
private InternetDialogController mInternetDialogController;
@@ -167,6 +180,10 @@
@Before
public void setUp() {
+ mStaticMockSession = mockitoSession()
+ .mockStatic(SubscriptionManager.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
MockitoAnnotations.initMocks(this);
mTestableResources = mContext.getOrCreateTestableResources();
doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
@@ -183,6 +200,7 @@
mAccessPoints.add(mWifiEntry1);
when(mAccessPointController.getMergedCarrierEntry()).thenReturn(mMergedCarrierEntry);
when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID});
+ when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(SUB_ID);
when(mToastFactory.createToast(any(), anyString(), anyString(), anyInt(), anyInt()))
.thenReturn(mSystemUIToast);
when(mSystemUIToast.getView()).thenReturn(mToastView);
@@ -196,7 +214,7 @@
mConnectivityManager, mHandler, mExecutor, mBroadcastDispatcher,
mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController,
mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker,
- mLocationController, mDialogLaunchAnimator, mWifiStateWorker);
+ mLocationController, mDialogLaunchAnimator, mWifiStateWorker, mFlags);
mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
mInternetDialogController.mOnSubscriptionsChangedListener);
mInternetDialogController.onStart(mInternetDialogCallback, true);
@@ -205,6 +223,11 @@
mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
}
+ @After
+ public void tearDown() {
+ mStaticMockSession.finishMocking();
+ }
+
@Test
public void connectCarrierNetwork_mergedCarrierEntryCanConnect_connectAndCreateSysUiToast() {
when(mTelephonyManager.isDataEnabled()).thenReturn(true);
@@ -387,15 +410,45 @@
@Test
public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ InternetDialogController spyController = spy(mInternetDialogController);
fakeAirplaneModeEnabled(false);
when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
- mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+ spyController.onAccessPointsChanged(null /* accessPoints */);
+
+ doReturn(SUB_ID2).when(spyController).getActiveAutoSwitchNonDdsSubId();
+ doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
+ doReturn(mServiceState).when(mTelephonyManager).getServiceState();
+ doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState();
+
+ assertFalse(TextUtils.equals(spyController.getSubtitleText(false),
+ getResourcesString("all_network_unavailable")));
+
+ doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .when(spyController).getActiveAutoSwitchNonDdsSubId();
+ spyController.onAccessPointsChanged(null /* accessPoints */);
+ assertTrue(TextUtils.equals(spyController.getSubtitleText(false),
+ getResourcesString("all_network_unavailable")));
+ }
+
+ @Test
+ public void getSubtitleText_withNoService_returnNoNetworksAvailable_flagOff() {
+ InternetDialogController spyController = spy(mInternetDialogController);
+ fakeAirplaneModeEnabled(false);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
+ spyController.onAccessPointsChanged(null /* accessPoints */);
doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
doReturn(mServiceState).when(mTelephonyManager).getServiceState();
doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState();
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
+ assertTrue(TextUtils.equals(spyController.getSubtitleText(false),
+ getResourcesString("all_network_unavailable")));
+
+ doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .when(spyController).getActiveAutoSwitchNonDdsSubId();
+ spyController.onAccessPointsChanged(null /* accessPoints */);
+ assertTrue(TextUtils.equals(spyController.getSubtitleText(false),
getResourcesString("all_network_unavailable")));
}
@@ -713,6 +766,108 @@
}
@Test
+ public void getSignalStrengthIcon_differentSubId() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ InternetDialogController spyController = spy(mInternetDialogController);
+ Drawable icons = spyController.getSignalStrengthIcon(SUB_ID, mContext, 1, 1, 0, false);
+ Drawable icons2 = spyController.getSignalStrengthIcon(SUB_ID2, mContext, 1, 1, 0, false);
+
+ assertThat(icons).isNotEqualTo(icons2);
+ }
+
+ @Test
+ public void getActiveAutoSwitchNonDdsSubId() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ // active on non-DDS
+ SubscriptionInfo info = mock(SubscriptionInfo.class);
+ doReturn(SUB_ID2).when(info).getSubscriptionId();
+ when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
+
+ int subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+ assertThat(subId).isEqualTo(SUB_ID2);
+
+ // active on CBRS
+ doReturn(true).when(info).isOpportunistic();
+ subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+ assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ // active on DDS
+ doReturn(false).when(info).isOpportunistic();
+ doReturn(SUB_ID).when(info).getSubscriptionId();
+ when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
+
+ subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+ assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+
+ @Test
+ public void getActiveAutoSwitchNonDdsSubId_flagOff() {
+ // active on non-DDS
+ SubscriptionInfo info = mock(SubscriptionInfo.class);
+ doReturn(SUB_ID2).when(info).getSubscriptionId();
+ when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
+
+ int subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+ assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+
+ @Test
+ public void getMobileNetworkSummary() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ InternetDialogController spyController = spy(mInternetDialogController);
+ doReturn(SUB_ID2).when(spyController).getActiveAutoSwitchNonDdsSubId();
+ doReturn(true).when(spyController).isMobileDataEnabled();
+ doReturn(true).when(spyController).activeNetworkIsCellular();
+ String dds = spyController.getMobileNetworkSummary(SUB_ID);
+ String nonDds = spyController.getMobileNetworkSummary(SUB_ID2);
+
+ assertThat(dds).contains(mContext.getString(R.string.mobile_data_poor_connection));
+ assertThat(dds).isNotEqualTo(nonDds);
+ }
+
+ @Test
+ public void getMobileNetworkSummary_flagOff() {
+ InternetDialogController spyController = spy(mInternetDialogController);
+ doReturn(true).when(spyController).isMobileDataEnabled();
+ doReturn(true).when(spyController).activeNetworkIsCellular();
+ String dds = spyController.getMobileNetworkSummary(SUB_ID);
+
+ assertThat(dds).contains(mContext.getString(R.string.mobile_data_connection_active));
+ }
+
+ @Test
+ public void launchMobileNetworkSettings_validSubId() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ InternetDialogController spyController = spy(mInternetDialogController);
+ doReturn(SUB_ID2).when(spyController).getActiveAutoSwitchNonDdsSubId();
+ spyController.launchMobileNetworkSettings(mDialogLaunchView);
+
+ verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt(),
+ any());
+ }
+
+ @Test
+ public void launchMobileNetworkSettings_invalidSubId() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ InternetDialogController spyController = spy(mInternetDialogController);
+ doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .when(spyController).getActiveAutoSwitchNonDdsSubId();
+ spyController.launchMobileNetworkSettings(mDialogLaunchView);
+
+ verify(mActivityStarter, never())
+ .postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
+ }
+
+ @Test
+ public void setAutoDataSwitchMobileDataPolicy() {
+ when(mFlags.isEnabled(any(UnreleasedFlag.class))).thenReturn(true);
+ mInternetDialogController.setAutoDataSwitchMobileDataPolicy(SUB_ID, true);
+
+ verify(mTelephonyManager).setMobileDataPolicyEnabled(eq(
+ TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH), eq(true));
+ }
+
+ @Test
public void getSignalStrengthDrawableWithLevel_carrierNetworkIsNotActive_useMobileDataLevel() {
// Fake mobile data level as SIGNAL_STRENGTH_POOR(1)
when(mSignalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_POOR);
@@ -720,9 +875,9 @@
when(mInternetDialogController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
InternetDialogController spyController = spy(mInternetDialogController);
- spyController.getSignalStrengthDrawableWithLevel(false /* isCarrierNetworkActive */);
+ spyController.getSignalStrengthDrawableWithLevel(false /* isCarrierNetworkActive */, 0);
- verify(spyController).getSignalStrengthIcon(any(), eq(SIGNAL_STRENGTH_POOR),
+ verify(spyController).getSignalStrengthIcon(eq(0), any(), eq(SIGNAL_STRENGTH_POOR),
eq(NUM_SIGNAL_STRENGTH_BINS), anyInt(), anyBoolean());
}
@@ -734,9 +889,9 @@
when(mInternetDialogController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
InternetDialogController spyController = spy(mInternetDialogController);
- spyController.getSignalStrengthDrawableWithLevel(true /* isCarrierNetworkActive */);
+ spyController.getSignalStrengthDrawableWithLevel(true /* isCarrierNetworkActive */, 0);
- verify(spyController).getSignalStrengthIcon(any(), eq(WIFI_LEVEL_MAX),
+ verify(spyController).getSignalStrengthIcon(eq(0), any(), eq(WIFI_LEVEL_MAX),
eq(WIFI_LEVEL_MAX + 1), anyInt(), anyBoolean());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index f922475..4084cf4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -8,12 +8,15 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
@@ -31,6 +34,7 @@
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -72,6 +76,8 @@
private InternetDialogController mInternetDialogController;
@Mock
private KeyguardStateController mKeyguard;
+ @Mock
+ private DialogLaunchAnimator mDialogLaunchAnimator;
private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
private InternetDialog mInternetDialog;
@@ -100,8 +106,9 @@
when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
when(mWifiEntries.size()).thenReturn(1);
- when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE);
- when(mInternetDialogController.getMobileNetworkSummary())
+ when(mInternetDialogController.getMobileNetworkTitle(anyInt()))
+ .thenReturn(MOBILE_NETWORK_TITLE);
+ when(mInternetDialogController.getMobileNetworkSummary(anyInt()))
.thenReturn(MOBILE_NETWORK_SUMMARY);
when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
@@ -115,7 +122,8 @@
private void createInternetDialog() {
mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
- mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler,
+ mInternetDialogController, true, true, true, mock(UiEventLogger.class),
+ mDialogLaunchAnimator, mHandler,
mBgExecutor, mKeyguard);
mInternetDialog.mAdapter = mInternetAdapter;
mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
@@ -307,12 +315,18 @@
@Test
public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
+ mInternetDialog.dismissDialog();
+ doReturn(true).when(mInternetDialogController).hasActiveSubId();
+ createInternetDialog();
// The preconditions WiFi ON and Internet WiFi are already in setUp()
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
- mInternetDialog.updateDialog(false);
+ mInternetDialog.updateDialog(true);
assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+ LinearLayout secondaryLayout = mDialogView.requireViewById(
+ R.id.secondary_mobile_network_layout);
+ assertThat(secondaryLayout.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -460,6 +474,44 @@
}
@Test
+ public void updateDialog_showSecondaryDataSub() {
+ mInternetDialog.dismissDialog();
+ doReturn(1).when(mInternetDialogController).getActiveAutoSwitchNonDdsSubId();
+ doReturn(true).when(mInternetDialogController).hasActiveSubId();
+ doReturn(false).when(mInternetDialogController).isAirplaneModeEnabled();
+ createInternetDialog();
+
+ clearInvocations(mInternetDialogController);
+ mInternetDialog.updateDialog(true);
+
+ LinearLayout primaryLayout = mDialogView.requireViewById(
+ R.id.mobile_network_layout);
+ LinearLayout secondaryLayout = mDialogView.requireViewById(
+ R.id.secondary_mobile_network_layout);
+
+ verify(mInternetDialogController).getMobileNetworkSummary(1);
+ assertThat(primaryLayout.getBackground()).isNotEqualTo(secondaryLayout.getBackground());
+
+ // Tap the primary sub info
+ primaryLayout.performClick();
+ ArgumentCaptor<AlertDialog> dialogArgumentCaptor =
+ ArgumentCaptor.forClass(AlertDialog.class);
+ verify(mDialogLaunchAnimator).showFromDialog(dialogArgumentCaptor.capture(),
+ eq(mInternetDialog), eq(null), eq(false));
+ AlertDialog dialog = dialogArgumentCaptor.getValue();
+ dialog.show();
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+ TestableLooper.get(this).processAllMessages();
+ verify(mInternetDialogController).setAutoDataSwitchMobileDataPolicy(1, false);
+
+ // Tap the secondary sub info
+ secondaryLayout.performClick();
+ verify(mInternetDialogController).launchMobileNetworkSettings(any(View.class));
+
+ dialog.dismiss();
+ }
+
+ @Test
public void updateDialog_wifiOn_hideWifiScanNotify() {
// The preconditions WiFi ON and WiFi entries are already in setUp()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index ffb41e5..70cbc64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Handler
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -104,13 +105,14 @@
mockContext,
mockPluginManager,
mockHandler,
- fakeDefaultProvider
+ isEnabled = true,
+ userHandle = UserHandle.USER_ALL,
+ defaultClockProvider = fakeDefaultProvider
) {
override var currentClockId: ClockId
get() = settingValue
set(value) { settingValue = value }
}
- registry.isEnabled = true
verify(mockPluginManager)
.addPluginListener(captor.capture(), eq(ClockProviderPlugin::class.java), eq(true))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
deleted file mode 100644
index 81b8e98..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.row;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.view.NotificationHeaderView;
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.internal.widget.NotificationActionListLayout;
-import com.android.internal.widget.NotificationExpandButton;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.media.dialog.MediaOutputDialogFactory;
-import com.android.systemui.statusbar.notification.FeedbackIcon;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NotificationContentViewTest extends SysuiTestCase {
-
- NotificationContentView mView;
-
- @Before
- @UiThreadTest
- public void setup() {
- mDependency.injectMockDependency(MediaOutputDialogFactory.class);
-
- mView = new NotificationContentView(mContext, null);
- ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
- ExpandableNotificationRow mockRow = spy(row);
- doReturn(10).when(mockRow).getIntrinsicHeight();
-
- mView.setContainingNotification(mockRow);
- mView.setHeights(10, 20, 30);
-
- mView.setContractedChild(createViewWithHeight(10));
- mView.setExpandedChild(createViewWithHeight(20));
- mView.setHeadsUpChild(createViewWithHeight(30));
-
- mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
- mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- }
-
- private View createViewWithHeight(int height) {
- View view = new View(mContext, null);
- view.setMinimumHeight(height);
- return view;
- }
-
- @Test
- @UiThreadTest
- public void testSetFeedbackIcon() {
- View mockContracted = mock(NotificationHeaderView.class);
- when(mockContracted.findViewById(com.android.internal.R.id.feedback))
- .thenReturn(mockContracted);
- when(mockContracted.getContext()).thenReturn(mContext);
- View mockExpanded = mock(NotificationHeaderView.class);
- when(mockExpanded.findViewById(com.android.internal.R.id.feedback))
- .thenReturn(mockExpanded);
- when(mockExpanded.getContext()).thenReturn(mContext);
- View mockHeadsUp = mock(NotificationHeaderView.class);
- when(mockHeadsUp.findViewById(com.android.internal.R.id.feedback))
- .thenReturn(mockHeadsUp);
- when(mockHeadsUp.getContext()).thenReturn(mContext);
-
- mView.setContractedChild(mockContracted);
- mView.setExpandedChild(mockExpanded);
- mView.setHeadsUpChild(mockHeadsUp);
-
- mView.setFeedbackIcon(new FeedbackIcon(R.drawable.ic_feedback_alerted,
- R.string.notification_feedback_indicator_alerted));
-
- verify(mockContracted, times(1)).setVisibility(View.VISIBLE);
- verify(mockExpanded, times(1)).setVisibility(View.VISIBLE);
- verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE);
- }
-
- @Test
- @UiThreadTest
- public void testExpandButtonFocusIsCalled() {
- View mockContractedEB = mock(NotificationExpandButton.class);
- View mockContracted = mock(NotificationHeaderView.class);
- when(mockContracted.animate()).thenReturn(mock(ViewPropertyAnimator.class));
- when(mockContracted.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
- mockContractedEB);
- when(mockContracted.getContext()).thenReturn(mContext);
-
- View mockExpandedEB = mock(NotificationExpandButton.class);
- View mockExpanded = mock(NotificationHeaderView.class);
- when(mockExpanded.animate()).thenReturn(mock(ViewPropertyAnimator.class));
- when(mockExpanded.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
- mockExpandedEB);
- when(mockExpanded.getContext()).thenReturn(mContext);
-
- View mockHeadsUpEB = mock(NotificationExpandButton.class);
- View mockHeadsUp = mock(NotificationHeaderView.class);
- when(mockHeadsUp.animate()).thenReturn(mock(ViewPropertyAnimator.class));
- when(mockHeadsUp.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
- mockHeadsUpEB);
- when(mockHeadsUp.getContext()).thenReturn(mContext);
-
- // Set up all 3 child forms
- mView.setContractedChild(mockContracted);
- mView.setExpandedChild(mockExpanded);
- mView.setHeadsUpChild(mockHeadsUp);
-
- // This is required to call requestAccessibilityFocus()
- mView.setFocusOnVisibilityChange();
-
- // The following will initialize the view and switch from not visible to expanded.
- // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
- mView.setHeadsUp(true);
-
- verify(mockContractedEB, times(0)).requestAccessibilityFocus();
- verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
- verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
- }
-
- @Test
- @UiThreadTest
- public void testRemoteInputVisibleSetsActionsUnimportantHideDescendantsForAccessibility() {
- View mockContracted = mock(NotificationHeaderView.class);
-
- View mockExpandedActions = mock(NotificationActionListLayout.class);
- View mockExpanded = mock(NotificationHeaderView.class);
- when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
- mockExpandedActions);
-
- View mockHeadsUpActions = mock(NotificationActionListLayout.class);
- View mockHeadsUp = mock(NotificationHeaderView.class);
- when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
- mockHeadsUpActions);
-
- mView.setContractedChild(mockContracted);
- mView.setExpandedChild(mockExpanded);
- mView.setHeadsUpChild(mockHeadsUp);
-
- mView.setRemoteInputVisible(true);
-
- verify(mockContracted, times(0)).findViewById(0);
- verify(mockExpandedActions, times(1)).setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- }
-
- @Test
- @UiThreadTest
- public void testRemoteInputInvisibleSetsActionsAutoImportantForAccessibility() {
- View mockContracted = mock(NotificationHeaderView.class);
-
- View mockExpandedActions = mock(NotificationActionListLayout.class);
- View mockExpanded = mock(NotificationHeaderView.class);
- when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
- mockExpandedActions);
-
- View mockHeadsUpActions = mock(NotificationActionListLayout.class);
- View mockHeadsUp = mock(NotificationHeaderView.class);
- when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
- mockHeadsUpActions);
-
- mView.setContractedChild(mockContracted);
- mView.setExpandedChild(mockExpanded);
- mView.setHeadsUpChild(mockHeadsUp);
-
- mView.setRemoteInputVisible(false);
-
- verify(mockContracted, times(0)).findViewById(0);
- verify(mockExpandedActions, times(1)).setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
new file mode 100644
index 0000000..562b4df
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.content.res.Resources
+import android.os.UserHandle
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.view.NotificationHeaderView
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.internal.widget.NotificationActionListLayout
+import com.android.internal.widget.NotificationExpandButton
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.media.dialog.MediaOutputDialogFactory
+import com.android.systemui.statusbar.notification.FeedbackIcon
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationContentViewTest : SysuiTestCase() {
+ private lateinit var view: NotificationContentView
+
+ @Mock private lateinit var mPeopleNotificationIdentifier: PeopleNotificationIdentifier
+
+ private val notificationContentMargin =
+ mContext.resources.getDimensionPixelSize(R.dimen.notification_content_margin)
+
+ @Before
+ fun setup() {
+ initMocks(this)
+
+ mDependency.injectMockDependency(MediaOutputDialogFactory::class.java)
+
+ view = spy(NotificationContentView(mContext, /* attrs= */ null))
+ val row = ExpandableNotificationRow(mContext, /* attrs= */ null)
+ row.entry = createMockNotificationEntry(false)
+ val spyRow = spy(row)
+ doReturn(10).whenever(spyRow).intrinsicHeight
+
+ with(view) {
+ initialize(mPeopleNotificationIdentifier, mock(), mock(), mock())
+ setContainingNotification(spyRow)
+ setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30)
+ contractedChild = createViewWithHeight(10)
+ expandedChild = createViewWithHeight(20)
+ headsUpChild = createViewWithHeight(30)
+ measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
+ layout(0, 0, view.measuredWidth, view.measuredHeight)
+ }
+ }
+
+ private fun createViewWithHeight(height: Int) =
+ View(mContext, /* attrs= */ null).apply { minimumHeight = height }
+
+ @Test
+ fun testSetFeedbackIcon() {
+ // Given: contractedChild, enpandedChild, and headsUpChild being set
+ val mockContracted = createMockNotificationHeaderView()
+ val mockExpanded = createMockNotificationHeaderView()
+ val mockHeadsUp = createMockNotificationHeaderView()
+
+ with(view) {
+ contractedChild = mockContracted
+ expandedChild = mockExpanded
+ headsUpChild = mockHeadsUp
+ }
+
+ // When: FeedBackIcon is set
+ view.setFeedbackIcon(
+ FeedbackIcon(
+ R.drawable.ic_feedback_alerted,
+ R.string.notification_feedback_indicator_alerted
+ )
+ )
+
+ // Then: contractedChild, enpandedChild, and headsUpChild should be set to be visible
+ verify(mockContracted).visibility = View.VISIBLE
+ verify(mockExpanded).visibility = View.VISIBLE
+ verify(mockHeadsUp).visibility = View.VISIBLE
+ }
+
+ private fun createMockNotificationHeaderView() =
+ mock<NotificationHeaderView>().apply {
+ whenever(this.findViewById<View>(R.id.feedback)).thenReturn(this)
+ whenever(this.context).thenReturn(mContext)
+ }
+
+ @Test
+ fun testExpandButtonFocusIsCalled() {
+ val mockContractedEB = mock<NotificationExpandButton>()
+ val mockContracted = createMockNotificationHeaderView(mockContractedEB)
+
+ val mockExpandedEB = mock<NotificationExpandButton>()
+ val mockExpanded = createMockNotificationHeaderView(mockExpandedEB)
+
+ val mockHeadsUpEB = mock<NotificationExpandButton>()
+ val mockHeadsUp = createMockNotificationHeaderView(mockHeadsUpEB)
+
+ // Set up all 3 child forms
+ view.contractedChild = mockContracted
+ view.expandedChild = mockExpanded
+ view.headsUpChild = mockHeadsUp
+
+ // This is required to call requestAccessibilityFocus()
+ view.setFocusOnVisibilityChange()
+
+ // The following will initialize the view and switch from not visible to expanded.
+ // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
+ view.setHeadsUp(true)
+ verify(mockContractedEB, never()).requestAccessibilityFocus()
+ verify(mockExpandedEB).requestAccessibilityFocus()
+ verify(mockHeadsUpEB, never()).requestAccessibilityFocus()
+ }
+
+ private fun createMockNotificationHeaderView(mockExpandedEB: NotificationExpandButton) =
+ mock<NotificationHeaderView>().apply {
+ whenever(this.animate()).thenReturn(mock())
+ whenever(this.findViewById<View>(R.id.expand_button)).thenReturn(mockExpandedEB)
+ whenever(this.context).thenReturn(mContext)
+ }
+
+ @Test
+ fun testRemoteInputVisibleSetsActionsUnimportantHideDescendantsForAccessibility() {
+ val mockContracted = mock<NotificationHeaderView>()
+
+ val mockExpandedActions = mock<NotificationActionListLayout>()
+ val mockExpanded = mock<NotificationHeaderView>()
+ whenever(mockExpanded.findViewById<View>(R.id.actions)).thenReturn(mockExpandedActions)
+
+ val mockHeadsUpActions = mock<NotificationActionListLayout>()
+ val mockHeadsUp = mock<NotificationHeaderView>()
+ whenever(mockHeadsUp.findViewById<View>(R.id.actions)).thenReturn(mockHeadsUpActions)
+
+ with(view) {
+ contractedChild = mockContracted
+ expandedChild = mockExpanded
+ headsUpChild = mockHeadsUp
+ }
+
+ view.setRemoteInputVisible(true)
+
+ verify(mockContracted, never()).findViewById<View>(0)
+ verify(mockExpandedActions).importantForAccessibility =
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ verify(mockHeadsUpActions).importantForAccessibility =
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ }
+
+ @Test
+ fun testRemoteInputInvisibleSetsActionsAutoImportantForAccessibility() {
+ val mockContracted = mock<NotificationHeaderView>()
+
+ val mockExpandedActions = mock<NotificationActionListLayout>()
+ val mockExpanded = mock<NotificationHeaderView>()
+ whenever(mockExpanded.findViewById<View>(R.id.actions)).thenReturn(mockExpandedActions)
+
+ val mockHeadsUpActions = mock<NotificationActionListLayout>()
+ val mockHeadsUp = mock<NotificationHeaderView>()
+ whenever(mockHeadsUp.findViewById<View>(R.id.actions)).thenReturn(mockHeadsUpActions)
+
+ with(view) {
+ contractedChild = mockContracted
+ expandedChild = mockExpanded
+ headsUpChild = mockHeadsUp
+ }
+
+ view.setRemoteInputVisible(false)
+
+ verify(mockContracted, never()).findViewById<View>(0)
+ verify(mockExpandedActions).importantForAccessibility =
+ View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
+ verify(mockHeadsUpActions).importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
+ }
+
+ @Test
+ fun setExpandedChild_notShowBubbleButton_marginTargetBottomMarginShouldNotChange() {
+ // Given: bottom margin of actionListMarginTarget is notificationContentMargin
+ // Bubble button should not be shown for the given NotificationEntry
+ val mockNotificationEntry = createMockNotificationEntry(/* showButton= */ false)
+ val mockContainingNotification = createMockContainingNotification(mockNotificationEntry)
+ val actionListMarginTarget =
+ spy(createLinearLayoutWithBottomMargin(notificationContentMargin))
+ val mockExpandedChild = createMockExpandedChild(mockNotificationEntry)
+ whenever(
+ mockExpandedChild.findViewById<LinearLayout>(
+ R.id.notification_action_list_margin_target
+ )
+ )
+ .thenReturn(actionListMarginTarget)
+ view.setContainingNotification(mockContainingNotification)
+
+ // When: call NotificationContentView.setExpandedChild() to set the expandedChild
+ view.expandedChild = mockExpandedChild
+
+ // Then: bottom margin of actionListMarginTarget should not change,
+ // still be notificationContentMargin
+ assertEquals(notificationContentMargin, getMarginBottom(actionListMarginTarget))
+ }
+
+ @Test
+ fun setExpandedChild_showBubbleButton_marginTargetBottomMarginShouldChangeToZero() {
+ // Given: bottom margin of actionListMarginTarget is notificationContentMargin
+ // Bubble button should be shown for the given NotificationEntry
+ val mockNotificationEntry = createMockNotificationEntry(/* showButton= */ true)
+ val mockContainingNotification = createMockContainingNotification(mockNotificationEntry)
+ val actionListMarginTarget =
+ spy(createLinearLayoutWithBottomMargin(notificationContentMargin))
+ val mockExpandedChild = createMockExpandedChild(mockNotificationEntry)
+ whenever(
+ mockExpandedChild.findViewById<LinearLayout>(
+ R.id.notification_action_list_margin_target
+ )
+ )
+ .thenReturn(actionListMarginTarget)
+ view.setContainingNotification(mockContainingNotification)
+
+ // When: call NotificationContentView.setExpandedChild() to set the expandedChild
+ view.expandedChild = mockExpandedChild
+
+ // Then: bottom margin of actionListMarginTarget should be set to 0
+ assertEquals(0, getMarginBottom(actionListMarginTarget))
+ }
+
+ @Test
+ fun onNotificationUpdated_notShowBubbleButton_marginTargetBottomMarginShouldNotChange() {
+ // Given: bottom margin of actionListMarginTarget is notificationContentMargin
+ val mockNotificationEntry = createMockNotificationEntry(/* showButton= */ false)
+ val mockContainingNotification = createMockContainingNotification(mockNotificationEntry)
+ val actionListMarginTarget =
+ spy(createLinearLayoutWithBottomMargin(notificationContentMargin))
+ val mockExpandedChild = createMockExpandedChild(mockNotificationEntry)
+ whenever(
+ mockExpandedChild.findViewById<LinearLayout>(
+ R.id.notification_action_list_margin_target
+ )
+ )
+ .thenReturn(actionListMarginTarget)
+ view.setContainingNotification(mockContainingNotification)
+ view.expandedChild = mockExpandedChild
+ assertEquals(notificationContentMargin, getMarginBottom(actionListMarginTarget))
+
+ // When: call NotificationContentView.onNotificationUpdated() to update the
+ // NotificationEntry, which should not show bubble button
+ view.onNotificationUpdated(createMockNotificationEntry(/* showButton= */ false))
+
+ // Then: bottom margin of actionListMarginTarget should not change, still be 20
+ assertEquals(notificationContentMargin, getMarginBottom(actionListMarginTarget))
+ }
+
+ @Test
+ fun onNotificationUpdated_showBubbleButton_marginTargetBottomMarginShouldChangeToZero() {
+ // Given: bottom margin of actionListMarginTarget is notificationContentMargin
+ val mockNotificationEntry = createMockNotificationEntry(/* showButton= */ false)
+ val mockContainingNotification = createMockContainingNotification(mockNotificationEntry)
+ val actionListMarginTarget =
+ spy(createLinearLayoutWithBottomMargin(notificationContentMargin))
+ val mockExpandedChild = createMockExpandedChild(mockNotificationEntry)
+ whenever(
+ mockExpandedChild.findViewById<LinearLayout>(
+ R.id.notification_action_list_margin_target
+ )
+ )
+ .thenReturn(actionListMarginTarget)
+ view.setContainingNotification(mockContainingNotification)
+ view.expandedChild = mockExpandedChild
+ assertEquals(notificationContentMargin, getMarginBottom(actionListMarginTarget))
+
+ // When: call NotificationContentView.onNotificationUpdated() to update the
+ // NotificationEntry, which should show bubble button
+ view.onNotificationUpdated(createMockNotificationEntry(true))
+
+ // Then: bottom margin of actionListMarginTarget should not change, still be 20
+ assertEquals(0, getMarginBottom(actionListMarginTarget))
+ }
+
+ private fun createMockContainingNotification(notificationEntry: NotificationEntry) =
+ mock<ExpandableNotificationRow>().apply {
+ whenever(this.entry).thenReturn(notificationEntry)
+ whenever(this.context).thenReturn(mContext)
+ whenever(this.bubbleClickListener).thenReturn(View.OnClickListener {})
+ }
+
+ private fun createMockNotificationEntry(showButton: Boolean) =
+ mock<NotificationEntry>().apply {
+ whenever(mPeopleNotificationIdentifier.getPeopleNotificationType(this))
+ .thenReturn(PeopleNotificationIdentifier.TYPE_FULL_PERSON)
+ whenever(this.bubbleMetadata).thenReturn(mock())
+ val sbnMock: StatusBarNotification = mock()
+ val userMock: UserHandle = mock()
+ whenever(this.sbn).thenReturn(sbnMock)
+ whenever(sbnMock.user).thenReturn(userMock)
+ doReturn(showButton).whenever(view).shouldShowBubbleButton(this)
+ }
+
+ private fun createLinearLayoutWithBottomMargin(bottomMargin: Int): LinearLayout {
+ val outerLayout = LinearLayout(mContext)
+ val innerLayout = LinearLayout(mContext)
+ outerLayout.addView(innerLayout)
+ val mlp = innerLayout.layoutParams as ViewGroup.MarginLayoutParams
+ mlp.setMargins(0, 0, 0, bottomMargin)
+ return innerLayout
+ }
+
+ private fun createMockExpandedChild(notificationEntry: NotificationEntry) =
+ mock<ExpandableNotificationRow>().apply {
+ whenever(this.findViewById<ImageView>(R.id.bubble_button)).thenReturn(mock())
+ whenever(this.findViewById<View>(R.id.actions_container)).thenReturn(mock())
+ whenever(this.entry).thenReturn(notificationEntry)
+ whenever(this.context).thenReturn(mContext)
+
+ val resourcesMock: Resources = mock()
+ whenever(resourcesMock.configuration).thenReturn(mock())
+ whenever(this.resources).thenReturn(resourcesMock)
+ }
+
+ private fun getMarginBottom(layout: LinearLayout): Int =
+ (layout.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 6de8bd5..5755782 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -235,6 +235,7 @@
@Mock private NavigationBarController mNavigationBarController;
@Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
@Mock private SysuiColorExtractor mColorExtractor;
+ private WakefulnessLifecycle mWakefulnessLifecycle;
@Mock private ColorExtractor.GradientColors mGradientColors;
@Mock private PulseExpansionHandler mPulseExpansionHandler;
@Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
@@ -366,10 +367,10 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- WakefulnessLifecycle wakefulnessLifecycle =
+ mWakefulnessLifecycle =
new WakefulnessLifecycle(mContext, mIWallpaperManager, mDumpManager);
- wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
- wakefulnessLifecycle.dispatchFinishedWakingUp();
+ mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+ mWakefulnessLifecycle.dispatchFinishedWakingUp();
when(mGradientColors.supportsDarkText()).thenReturn(true);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
@@ -428,7 +429,7 @@
mBatteryController,
mColorExtractor,
new ScreenLifecycle(mDumpManager),
- wakefulnessLifecycle,
+ mWakefulnessLifecycle,
mStatusBarStateController,
Optional.of(mBubbles),
mDeviceProvisionedController,
@@ -507,6 +508,8 @@
mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController;
mCentralSurfaces.mBarService = mBarService;
mCentralSurfaces.mStackScroller = mStackScroller;
+ mCentralSurfaces.mGestureWakeLock = mPowerManager.newWakeLock(
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "sysui:GestureWakeLock");
mCentralSurfaces.startKeyguard();
mInitController.executePostInitTasks();
notificationLogger.setUpWithContainer(mNotificationListContainer);
@@ -1125,6 +1128,55 @@
assertThat(onDismissActionCaptor.getValue().onDismiss()).isFalse();
}
+ @Test
+ public void testKeyguardHideDelayedIfOcclusionAnimationRunning() {
+ // Show the keyguard and verify we've done so.
+ setKeyguardShowingAndOccluded(true /* showing */, false /* occluded */);
+ verify(mStatusBarStateController).setState(StatusBarState.KEYGUARD);
+
+ // Request to hide the keyguard, but while the occlude animation is playing. We should delay
+ // this hide call, since we're playing the occlude animation over the keyguard and thus want
+ // it to remain visible.
+ when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(true);
+ setKeyguardShowingAndOccluded(false /* showing */, true /* occluded */);
+ verify(mStatusBarStateController, never()).setState(StatusBarState.SHADE);
+
+ // Once the animation ends, verify that the keyguard is actually hidden.
+ when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(false);
+ setKeyguardShowingAndOccluded(false /* showing */, true /* occluded */);
+ verify(mStatusBarStateController).setState(StatusBarState.SHADE);
+ }
+
+ @Test
+ public void testKeyguardHideNotDelayedIfOcclusionAnimationNotRunning() {
+ // Show the keyguard and verify we've done so.
+ setKeyguardShowingAndOccluded(true /* showing */, false /* occluded */);
+ verify(mStatusBarStateController).setState(StatusBarState.KEYGUARD);
+
+ // Hide the keyguard while the occlusion animation is not running. Verify that we
+ // immediately hide the keyguard.
+ when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(false);
+ setKeyguardShowingAndOccluded(false /* showing */, true /* occluded */);
+ verify(mStatusBarStateController).setState(StatusBarState.SHADE);
+ }
+
+ /**
+ * Configures the appropriate mocks and then calls {@link CentralSurfacesImpl#updateIsKeyguard}
+ * to reconfigure the keyguard to reflect the requested showing/occluded states.
+ */
+ private void setKeyguardShowingAndOccluded(boolean showing, boolean occluded) {
+ when(mStatusBarStateController.isKeyguardRequested()).thenReturn(showing);
+ when(mKeyguardStateController.isOccluded()).thenReturn(occluded);
+
+ // If we want to show the keyguard, make sure that we think we're awake and not unlocking.
+ if (showing) {
+ when(mBiometricUnlockController.isWakeAndUnlock()).thenReturn(false);
+ mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+ }
+
+ mCentralSurfaces.updateIsKeyguard(false /* forceStateChange */);
+ }
+
private void setDeviceState(int state) {
ArgumentCaptor<DeviceStateManager.DeviceStateCallback> callbackCaptor =
ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
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 4d1a52c..a5deaa4 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
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
@@ -58,6 +59,7 @@
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.policy.FakeConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -117,6 +119,7 @@
// 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.)
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private KeyguardViewMediator mKeyguardViewMediator;
private static class AnimatorListener implements Animator.AnimatorListener {
private int mNumStarts;
@@ -230,7 +233,8 @@
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mKeyguardViewMediator);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -239,6 +243,8 @@
mScrimController.setWallpaperSupportsAmbientMode(false);
mScrimController.transitionTo(ScrimState.KEYGUARD);
finishAnimationsImmediately();
+
+ mScrimController.setLaunchingAffordanceWithPreview(false);
}
@After
@@ -852,7 +858,8 @@
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mKeyguardViewMediator);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1592,6 +1599,30 @@
assertScrimAlpha(mScrimBehind, 0);
}
+ @Test
+ public void keyguardAlpha_whenUnlockedForOcclusion_ifPlayingOcclusionAnimation() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+
+ when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(true);
+
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(mNotificationsScrim, (int) (KEYGUARD_SCRIM_ALPHA * 255f));
+ }
+
+ @Test
+ public void keyguardAlpha_whenUnlockedForLaunch_ifLaunchingAffordance() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(true);
+ mScrimController.setLaunchingAffordanceWithPreview(true);
+
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(mNotificationsScrim, (int) (KEYGUARD_SCRIM_ALPHA * 255f));
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
new file mode 100644
index 0000000..6ff7b7c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -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.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeMobileConnectionRepository : MobileConnectionRepository {
+ private val _subscriptionsModelFlow = MutableStateFlow(MobileSubscriptionModel())
+ override val subscriptionModelFlow: Flow<MobileSubscriptionModel> = _subscriptionsModelFlow
+
+ fun setMobileSubscriptionModel(model: MobileSubscriptionModel) {
+ _subscriptionsModelFlow.value = model
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileSubscriptionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
similarity index 66%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileSubscriptionRepository.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 0d15268..c88d468 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileSubscriptionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -18,11 +18,11 @@
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.settingslib.mobile.MobileMappings.Config
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeMobileSubscriptionRepository : MobileSubscriptionRepository {
+class FakeMobileConnectionsRepository : MobileConnectionsRepository {
private val _subscriptionsFlow = MutableStateFlow<List<SubscriptionInfo>>(listOf())
override val subscriptionsFlow: Flow<List<SubscriptionInfo>> = _subscriptionsFlow
@@ -30,22 +30,27 @@
MutableStateFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
- private val subIdFlows = mutableMapOf<Int, MutableStateFlow<MobileSubscriptionModel>>()
- override fun getFlowForSubId(subId: Int): Flow<MobileSubscriptionModel> {
- return subIdFlows[subId]
- ?: MutableStateFlow(MobileSubscriptionModel()).also { subIdFlows[subId] = it }
+ private val _defaultDataSubRatConfig = MutableStateFlow(Config())
+ override val defaultDataSubRatConfig = _defaultDataSubRatConfig
+
+ private val subIdRepos = mutableMapOf<Int, MobileConnectionRepository>()
+ override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
+ return subIdRepos[subId] ?: FakeMobileConnectionRepository().also { subIdRepos[subId] = it }
}
fun setSubscriptions(subs: List<SubscriptionInfo>) {
_subscriptionsFlow.value = subs
}
+ fun setDefaultDataSubRatConfig(config: Config) {
+ _defaultDataSubRatConfig.value = config
+ }
+
fun setActiveMobileDataSubscriptionId(subId: Int) {
_activeMobileDataSubscriptionId.value = subId
}
- fun setMobileSubscriptionModel(model: MobileSubscriptionModel, subId: Int) {
- val subscription = subIdFlows[subId] ?: throw Exception("no flow exists for this subId yet")
- subscription.value = model
+ fun setMobileConnectionRepositoryForId(subId: Int, repo: MobileConnectionRepository) {
+ subIdRepos[subId] = repo
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
new file mode 100644
index 0000000..775e6db
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class MobileConnectionRepositoryTest : SysuiTestCase() {
+ private lateinit var underTest: MobileConnectionRepositoryImpl
+
+ @Mock private lateinit var subscriptionManager: SubscriptionManager
+ @Mock private lateinit var telephonyManager: TelephonyManager
+ @Mock private lateinit var logger: ConnectivityPipelineLogger
+
+ private val scope = CoroutineScope(IMMEDIATE)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
+
+ underTest =
+ MobileConnectionRepositoryImpl(
+ SUB_1_ID,
+ telephonyManager,
+ IMMEDIATE,
+ logger,
+ scope,
+ )
+ }
+
+ @After
+ fun tearDown() {
+ scope.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_default() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(MobileSubscriptionModel())
+
+ job.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_emergencyOnly() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val serviceState = ServiceState()
+ serviceState.isEmergencyOnly = true
+
+ getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+
+ assertThat(latest?.isEmergencyOnly).isEqualTo(true)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_emergencyOnly_toggles() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<ServiceStateListener>()
+ val serviceState = ServiceState()
+ serviceState.isEmergencyOnly = true
+ callback.onServiceStateChanged(serviceState)
+ serviceState.isEmergencyOnly = false
+ callback.onServiceStateChanged(serviceState)
+
+ assertThat(latest?.isEmergencyOnly).isEqualTo(false)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_signalStrengths_levelsUpdate() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+ val strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+ callback.onSignalStrengthsChanged(strength)
+
+ assertThat(latest?.isGsm).isEqualTo(true)
+ assertThat(latest?.primaryLevel).isEqualTo(1)
+ assertThat(latest?.cdmaLevel).isEqualTo(2)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_dataConnectionState() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback =
+ getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+ callback.onDataConnectionStateChanged(100, 200 /* unused */)
+
+ assertThat(latest?.dataConnectionState).isEqualTo(100)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_dataActivity() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.DataActivityListener>()
+ callback.onDataActivity(3)
+
+ assertThat(latest?.dataActivityDirection).isEqualTo(3)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testFlowForSubId_carrierNetworkChange() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.CarrierNetworkListener>()
+ callback.onCarrierNetworkChange(true)
+
+ assertThat(latest?.carrierNetworkChangeActive).isEqualTo(true)
+
+ job.cancel()
+ }
+
+ @Test
+ fun subscriptionFlow_networkType_default() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val type = NETWORK_TYPE_UNKNOWN
+ val expected = DefaultNetworkType(type)
+
+ assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun subscriptionFlow_networkType_updatesUsingDefault() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+ val type = NETWORK_TYPE_LTE
+ val expected = DefaultNetworkType(type)
+ val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
+ callback.onDisplayInfoChanged(ti)
+
+ assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun subscriptionFlow_networkType_updatesUsingOverride() =
+ runBlocking(IMMEDIATE) {
+ var latest: MobileSubscriptionModel? = null
+ val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+ val type = OVERRIDE_NETWORK_TYPE_LTE_CA
+ val expected = OverrideNetworkType(type)
+ val ti =
+ mock<TelephonyDisplayInfo>().also {
+ whenever(it.overrideNetworkType).thenReturn(type)
+ }
+ callback.onDisplayInfoChanged(ti)
+
+ assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ private fun getTelephonyCallbacks(): List<TelephonyCallback> {
+ val callbackCaptor = argumentCaptor<TelephonyCallback>()
+ Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.allValues
+ }
+
+ private inline fun <reified T> getTelephonyCallbackForType(): T {
+ val cbs = getTelephonyCallbacks().filterIsInstance<T>()
+ assertThat(cbs.size).isEqualTo(1)
+ return cbs[0]
+ }
+
+ /** Convenience constructor for SignalStrength */
+ private fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
+ val signalStrength = mock<SignalStrength>()
+ whenever(signalStrength.isGsm).thenReturn(isGsm)
+ whenever(signalStrength.level).thenReturn(gsmLevel)
+ val cdmaStrength =
+ mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
+ whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
+ .thenReturn(listOf(cdmaStrength))
+
+ return signalStrength
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ private const val SUB_1_ID = 1
+ private val SUB_1 =
+ mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
new file mode 100644
index 0000000..326e0d281
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class MobileConnectionsRepositoryTest : SysuiTestCase() {
+ private lateinit var underTest: MobileConnectionsRepositoryImpl
+
+ @Mock private lateinit var subscriptionManager: SubscriptionManager
+ @Mock private lateinit var telephonyManager: TelephonyManager
+ @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+
+ private val scope = CoroutineScope(IMMEDIATE)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(
+ broadcastDispatcher.broadcastFlow(
+ any(),
+ nullable(),
+ ArgumentMatchers.anyInt(),
+ nullable(),
+ )
+ )
+ .thenReturn(flowOf(Unit))
+
+ underTest =
+ MobileConnectionsRepositoryImpl(
+ subscriptionManager,
+ telephonyManager,
+ logger,
+ broadcastDispatcher,
+ context,
+ IMMEDIATE,
+ scope,
+ mock(),
+ )
+ }
+
+ @After
+ fun tearDown() {
+ scope.cancel()
+ }
+
+ @Test
+ fun testSubscriptions_initiallyEmpty() =
+ runBlocking(IMMEDIATE) {
+ assertThat(underTest.subscriptionsFlow.value).isEqualTo(listOf<SubscriptionInfo>())
+ }
+
+ @Test
+ fun testSubscriptions_listUpdates() =
+ runBlocking(IMMEDIATE) {
+ var latest: List<SubscriptionInfo>? = null
+
+ val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
+
+ job.cancel()
+ }
+
+ @Test
+ fun testSubscriptions_removingSub_updatesList() =
+ runBlocking(IMMEDIATE) {
+ var latest: List<SubscriptionInfo>? = null
+
+ val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this)
+
+ // WHEN 2 networks show up
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // WHEN one network is removed
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // THEN the subscriptions list represents the newest change
+ assertThat(latest).isEqualTo(listOf(SUB_2))
+
+ job.cancel()
+ }
+
+ @Test
+ fun testActiveDataSubscriptionId_initialValueIsInvalidId() =
+ runBlocking(IMMEDIATE) {
+ assertThat(underTest.activeMobileDataSubscriptionId.value)
+ .isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ }
+
+ @Test
+ fun testActiveDataSubscriptionId_updates() =
+ runBlocking(IMMEDIATE) {
+ var active: Int? = null
+
+ val job = underTest.activeMobileDataSubscriptionId.onEach { active = it }.launchIn(this)
+
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+ assertThat(active).isEqualTo(SUB_2_ID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testConnectionRepository_validSubId_isCached() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptionsFlow.launchIn(this)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_1_ID)
+
+ assertThat(repo1).isSameInstanceAs(repo2)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testConnectionCache_clearsInvalidSubscriptions() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptionsFlow.launchIn(this)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Get repos to trigger caching
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+
+ assertThat(underTest.getSubIdRepoCache())
+ .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
+
+ // SUB_2 disappears
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testConnectionRepository_invalidSubId_throws() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptionsFlow.launchIn(this)
+
+ assertThrows(IllegalArgumentException::class.java) {
+ underTest.getRepoForSubId(SUB_1_ID)
+ }
+
+ job.cancel()
+ }
+
+ private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
+ val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
+ verify(subscriptionManager)
+ .addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
+ return callbackCaptor.value!!
+ }
+
+ private fun getTelephonyCallbacks(): List<TelephonyCallback> {
+ val callbackCaptor = argumentCaptor<TelephonyCallback>()
+ verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.allValues
+ }
+
+ private inline fun <reified T> getTelephonyCallbackForType(): T {
+ val cbs = getTelephonyCallbacks().filterIsInstance<T>()
+ assertThat(cbs.size).isEqualTo(1)
+ return cbs[0]
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ private const val SUB_1_ID = 1
+ private val SUB_1 =
+ mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
+
+ private const val SUB_2_ID = 2
+ private val SUB_2 =
+ mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepositoryTest.kt
deleted file mode 100644
index 316b795..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepositoryTest.kt
+++ /dev/null
@@ -1,360 +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 com.android.systemui.statusbar.pipeline.mobile.data.repository
-
-import android.telephony.CellSignalStrengthCdma
-import android.telephony.ServiceState
-import android.telephony.SignalStrength
-import android.telephony.SubscriptionInfo
-import android.telephony.SubscriptionManager
-import android.telephony.TelephonyCallback
-import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
-import android.telephony.TelephonyCallback.CarrierNetworkListener
-import android.telephony.TelephonyCallback.DataActivityListener
-import android.telephony.TelephonyCallback.DataConnectionStateListener
-import android.telephony.TelephonyCallback.DisplayInfoListener
-import android.telephony.TelephonyCallback.ServiceStateListener
-import android.telephony.TelephonyCallback.SignalStrengthsListener
-import android.telephony.TelephonyDisplayInfo
-import android.telephony.TelephonyManager
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-class MobileSubscriptionRepositoryTest : SysuiTestCase() {
- private lateinit var underTest: MobileSubscriptionRepositoryImpl
-
- @Mock private lateinit var subscriptionManager: SubscriptionManager
- @Mock private lateinit var telephonyManager: TelephonyManager
- private val scope = CoroutineScope(IMMEDIATE)
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- underTest =
- MobileSubscriptionRepositoryImpl(
- subscriptionManager,
- telephonyManager,
- IMMEDIATE,
- scope,
- )
- }
-
- @After
- fun tearDown() {
- scope.cancel()
- }
-
- @Test
- fun testSubscriptions_initiallyEmpty() =
- runBlocking(IMMEDIATE) {
- assertThat(underTest.subscriptionsFlow.value).isEqualTo(listOf<SubscriptionInfo>())
- }
-
- @Test
- fun testSubscriptions_listUpdates() =
- runBlocking(IMMEDIATE) {
- var latest: List<SubscriptionInfo>? = null
-
- val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this)
-
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_2))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
-
- job.cancel()
- }
-
- @Test
- fun testSubscriptions_removingSub_updatesList() =
- runBlocking(IMMEDIATE) {
- var latest: List<SubscriptionInfo>? = null
-
- val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this)
-
- // WHEN 2 networks show up
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_2))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // WHEN one network is removed
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_2))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // THEN the subscriptions list represents the newest change
- assertThat(latest).isEqualTo(listOf(SUB_2))
-
- job.cancel()
- }
-
- @Test
- fun testActiveDataSubscriptionId_initialValueIsInvalidId() =
- runBlocking(IMMEDIATE) {
- assertThat(underTest.activeMobileDataSubscriptionId.value)
- .isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
- }
-
- @Test
- fun testActiveDataSubscriptionId_updates() =
- runBlocking(IMMEDIATE) {
- var active: Int? = null
-
- val job = underTest.activeMobileDataSubscriptionId.onEach { active = it }.launchIn(this)
-
- getActiveDataSubscriptionCallback().onActiveDataSubscriptionIdChanged(SUB_2_ID)
-
- assertThat(active).isEqualTo(SUB_2_ID)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_default() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isEqualTo(MobileSubscriptionModel())
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_emergencyOnly() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val serviceState = ServiceState()
- serviceState.isEmergencyOnly = true
-
- getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
-
- assertThat(latest?.isEmergencyOnly).isEqualTo(true)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_emergencyOnly_toggles() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val callback = getTelephonyCallbackForType<ServiceStateListener>()
- val serviceState = ServiceState()
- serviceState.isEmergencyOnly = true
- callback.onServiceStateChanged(serviceState)
- serviceState.isEmergencyOnly = false
- callback.onServiceStateChanged(serviceState)
-
- assertThat(latest?.isEmergencyOnly).isEqualTo(false)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_signalStrengths_levelsUpdate() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val callback = getTelephonyCallbackForType<SignalStrengthsListener>()
- val strength = signalStrength(1, 2, true)
- callback.onSignalStrengthsChanged(strength)
-
- assertThat(latest?.isGsm).isEqualTo(true)
- assertThat(latest?.primaryLevel).isEqualTo(1)
- assertThat(latest?.cdmaLevel).isEqualTo(2)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_dataConnectionState() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val callback = getTelephonyCallbackForType<DataConnectionStateListener>()
- callback.onDataConnectionStateChanged(100, 200 /* unused */)
-
- assertThat(latest?.dataConnectionState).isEqualTo(100)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_dataActivity() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val callback = getTelephonyCallbackForType<DataActivityListener>()
- callback.onDataActivity(3)
-
- assertThat(latest?.dataActivityDirection).isEqualTo(3)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_carrierNetworkChange() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val callback = getTelephonyCallbackForType<CarrierNetworkListener>()
- callback.onCarrierNetworkChange(true)
-
- assertThat(latest?.carrierNetworkChangeActive).isEqualTo(true)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_displayInfo() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- val callback = getTelephonyCallbackForType<DisplayInfoListener>()
- val ti = mock<TelephonyDisplayInfo>()
- callback.onDisplayInfoChanged(ti)
-
- assertThat(latest?.displayInfo).isEqualTo(ti)
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_isCached() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- val state1 = underTest.getFlowForSubId(SUB_1_ID)
- val state2 = underTest.getFlowForSubId(SUB_1_ID)
-
- assertThat(state1).isEqualTo(state2)
- }
-
- @Test
- fun testFlowForSubId_isRemovedAfterFinish() =
- runBlocking(IMMEDIATE) {
- whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
-
- var latest: MobileSubscriptionModel? = null
-
- // Start collecting on some flow
- val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
-
- // There should be once cached flow now
- assertThat(underTest.getSubIdFlowCache().size).isEqualTo(1)
-
- // When the job is canceled, the cache should be cleared
- job.cancel()
-
- assertThat(underTest.getSubIdFlowCache().size).isEqualTo(0)
- }
-
- private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
- val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
- verify(subscriptionManager)
- .addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
- }
-
- private fun getActiveDataSubscriptionCallback(): ActiveDataSubscriptionIdListener =
- getTelephonyCallbackForType()
-
- private fun getTelephonyCallbacks(): List<TelephonyCallback> {
- val callbackCaptor = argumentCaptor<TelephonyCallback>()
- verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
- return callbackCaptor.allValues
- }
-
- private inline fun <reified T> getTelephonyCallbackForType(): T {
- val cbs = getTelephonyCallbacks().filterIsInstance<T>()
- assertThat(cbs.size).isEqualTo(1)
- return cbs[0]
- }
-
- /** Convenience constructor for SignalStrength */
- private fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
- val signalStrength = mock<SignalStrength>()
- whenever(signalStrength.isGsm).thenReturn(isGsm)
- whenever(signalStrength.level).thenReturn(gsmLevel)
- val cdmaStrength =
- mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
- whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
- .thenReturn(listOf(cdmaStrength))
-
- return signalStrength
- }
-
- companion object {
- private val IMMEDIATE = Dispatchers.Main.immediate
- private const val SUB_1_ID = 1
- private val SUB_1 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
-
- private const val SUB_2_ID = 2
- private val SUB_2 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index 8ec68f3..cd4dbeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -23,7 +23,7 @@
class FakeMobileIconInteractor : MobileIconInteractor {
private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.UNKNOWN)
- override val iconGroup = _iconGroup
+ override val networkTypeIconGroup = _iconGroup
private val _isEmergencyOnly = MutableStateFlow<Boolean>(false)
override val isEmergencyOnly = _isEmergencyOnly
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
new file mode 100644
index 0000000..2bd2286
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
+import android.telephony.TelephonyManager.NETWORK_TYPE_GSM
+import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeMobileIconsInteractor(private val mobileMappings: MobileMappingsProxy) :
+ MobileIconsInteractor {
+ val THREE_G_KEY = mobileMappings.toIconKey(THREE_G)
+ val LTE_KEY = mobileMappings.toIconKey(LTE)
+ val FOUR_G_KEY = mobileMappings.toIconKey(FOUR_G)
+ val FIVE_G_OVERRIDE_KEY = mobileMappings.toIconKeyOverride(FIVE_G_OVERRIDE)
+
+ /**
+ * To avoid a reliance on [MobileMappings], we'll build a simpler map from network type to
+ * mobile icon. See TelephonyManager.NETWORK_TYPES for a list of types and [TelephonyIcons] for
+ * the exhaustive set of icons
+ */
+ val TEST_MAPPING: Map<String, MobileIconGroup> =
+ mapOf(
+ THREE_G_KEY to TelephonyIcons.THREE_G,
+ LTE_KEY to TelephonyIcons.LTE,
+ FOUR_G_KEY to TelephonyIcons.FOUR_G,
+ FIVE_G_OVERRIDE_KEY to TelephonyIcons.NR_5G,
+ )
+
+ private val _filteredSubscriptions = MutableStateFlow<List<SubscriptionInfo>>(listOf())
+ override val filteredSubscriptions = _filteredSubscriptions
+
+ private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
+ override val defaultMobileIconMapping = _defaultMobileIconMapping
+
+ private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
+ override val defaultMobileIconGroup = _defaultMobileIconGroup
+
+ private val _isUserSetup = MutableStateFlow(true)
+ override val isUserSetup = _isUserSetup
+
+ /** Always returns a new fake interactor */
+ override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
+ return FakeMobileIconInteractor()
+ }
+
+ companion object {
+ val DEFAULT_ICON = TelephonyIcons.G
+
+ // Use [MobileMappings] to define some simple definitions
+ const val THREE_G = NETWORK_TYPE_GSM
+ const val LTE = NETWORK_TYPE_LTE
+ const val FOUR_G = NETWORK_TYPE_UMTS
+ const val FIVE_G_OVERRIDE = OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 2f07d9c..ff44af4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -18,10 +18,19 @@
import android.telephony.CellSignalStrength
import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileSubscriptionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -29,26 +38,33 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
import org.junit.Before
import org.junit.Test
@SmallTest
class MobileIconInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconInteractor
- private val mobileSubscriptionRepository = FakeMobileSubscriptionRepository()
- private val sub1Flow = mobileSubscriptionRepository.getFlowForSubId(SUB_1_ID)
+ private val mobileMappingsProxy = FakeMobileMappingsProxy()
+ private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy)
+ private val connectionRepository = FakeMobileConnectionRepository()
@Before
fun setUp() {
- underTest = MobileIconInteractorImpl(sub1Flow)
+ underTest =
+ MobileIconInteractorImpl(
+ mobileIconsInteractor.defaultMobileIconMapping,
+ mobileIconsInteractor.defaultMobileIconGroup,
+ mobileMappingsProxy,
+ connectionRepository,
+ )
}
@Test
fun gsm_level_default_unknown() =
runBlocking(IMMEDIATE) {
- mobileSubscriptionRepository.setMobileSubscriptionModel(
+ connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(isGsm = true),
- SUB_1_ID
)
var latest: Int? = null
@@ -62,13 +78,12 @@
@Test
fun gsm_usesGsmLevel() =
runBlocking(IMMEDIATE) {
- mobileSubscriptionRepository.setMobileSubscriptionModel(
+ connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(
isGsm = true,
primaryLevel = GSM_LEVEL,
cdmaLevel = CDMA_LEVEL
),
- SUB_1_ID
)
var latest: Int? = null
@@ -82,9 +97,8 @@
@Test
fun cdma_level_default_unknown() =
runBlocking(IMMEDIATE) {
- mobileSubscriptionRepository.setMobileSubscriptionModel(
+ connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(isGsm = false),
- SUB_1_ID
)
var latest: Int? = null
@@ -97,13 +111,12 @@
@Test
fun cdma_usesCdmaLevel() =
runBlocking(IMMEDIATE) {
- mobileSubscriptionRepository.setMobileSubscriptionModel(
+ connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(
isGsm = false,
primaryLevel = GSM_LEVEL,
cdmaLevel = CDMA_LEVEL
),
- SUB_1_ID
)
var latest: Int? = null
@@ -114,6 +127,75 @@
job.cancel()
}
+ @Test
+ fun iconGroup_three_g() =
+ runBlocking(IMMEDIATE) {
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(TelephonyIcons.THREE_G)
+
+ job.cancel()
+ }
+
+ @Test
+ fun iconGroup_updates_on_change() =
+ runBlocking(IMMEDIATE) {
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(
+ resolvedNetworkType = DefaultNetworkType(FOUR_G),
+ ),
+ )
+ yield()
+
+ assertThat(latest).isEqualTo(TelephonyIcons.FOUR_G)
+
+ job.cancel()
+ }
+
+ @Test
+ fun iconGroup_5g_override_type() =
+ runBlocking(IMMEDIATE) {
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(resolvedNetworkType = OverrideNetworkType(FIVE_G_OVERRIDE)),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(TelephonyIcons.NR_5G)
+
+ job.cancel()
+ }
+
+ @Test
+ fun iconGroup_default_if_no_lookup() =
+ runBlocking(IMMEDIATE) {
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(
+ resolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN),
+ ),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(FakeMobileIconsInteractor.DEFAULT_ICON)
+
+ job.cancel()
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
@@ -123,9 +205,5 @@
private const val SUB_1_ID = 1
private val SUB_1 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
-
- private const val SUB_2_ID = 2
- private val SUB_2 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 89ad9cb..b01efd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -19,12 +19,14 @@
import android.telephony.SubscriptionInfo
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileSubscriptionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -39,7 +41,9 @@
class MobileIconsInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconsInteractor
private val userSetupRepository = FakeUserSetupRepository()
- private val subscriptionsRepository = FakeMobileSubscriptionRepository()
+ private val subscriptionsRepository = FakeMobileConnectionsRepository()
+ private val mobileMappingsProxy = FakeMobileMappingsProxy()
+ private val scope = CoroutineScope(IMMEDIATE)
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
@@ -47,10 +51,12 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
underTest =
- MobileIconsInteractor(
+ MobileIconsInteractorImpl(
subscriptionsRepository,
carrierConfigTracker,
+ mobileMappingsProxy,
userSetupRepository,
+ scope
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeMobileMappingsProxy.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeMobileMappingsProxy.kt
new file mode 100644
index 0000000..6d8d902
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeMobileMappingsProxy.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.util
+
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.settingslib.mobile.TelephonyIcons
+
+class FakeMobileMappingsProxy : MobileMappingsProxy {
+ private var iconMap = mapOf<String, MobileIconGroup>()
+ private var defaultIcons = TelephonyIcons.THREE_G
+
+ fun setIconMap(map: Map<String, MobileIconGroup>) {
+ iconMap = map
+ }
+ override fun mapIconSets(config: Config): Map<String, MobileIconGroup> = iconMap
+ fun getIconMap() = iconMap
+
+ fun setDefaultIcons(group: MobileIconGroup) {
+ defaultIcons = group
+ }
+ override fun getDefaultIcons(config: Config): MobileIconGroup = defaultIcons
+ fun getDefaultIcons(): MobileIconGroup = defaultIcons
+
+ override fun toIconKey(networkType: Int): String {
+ return networkType.toString()
+ }
+
+ override fun toIconKeyOverride(networkType: Int): String {
+ return toIconKey(networkType) + "_override"
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index 8d171be..69575a9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -26,7 +26,9 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatcher
import org.mockito.Mockito
+import org.mockito.Mockito.`when`
import org.mockito.stubbing.OngoingStubbing
+import org.mockito.stubbing.Stubber
/**
* Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
@@ -89,7 +91,8 @@
*
* @see Mockito.when
*/
-fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
+fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
+fun <T> Stubber.whenever(mock: T): T = `when`(mock)
/**
* A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 346fc6c..3cfae60 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -104,8 +104,6 @@
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TypedValue;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -124,6 +122,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.IRemoteViewsFactory;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.WidgetBackupProvider;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index 92435d0..3ea1bcb 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -23,8 +23,9 @@
import android.os.Build;
import android.text.TextUtils;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import java.io.IOException;
import java.util.Objects;
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index eac98f2..f0492a8 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -376,6 +376,16 @@
return;
}
+ // In some cases there may not be a monitor passed in when creating this task. So, if we
+ // don't have one already we ask the transport for a monitor.
+ if (mMonitor == null) {
+ try {
+ mMonitor = transport.getBackupManagerMonitor();
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to retrieve monitor from transport");
+ }
+ }
+
// Set up to send data to the transport
final int N = mPackages.size();
final byte[] buffer = new byte[8192];
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 03796ea..95cc289 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -21,6 +21,7 @@
import static com.android.server.backup.BackupManagerService.TAG;
import android.app.backup.BackupManager.OperationType;
+import android.app.backup.IBackupManagerMonitor;
import android.app.backup.RestoreSet;
import android.os.Handler;
import android.os.HandlerThread;
@@ -203,6 +204,14 @@
}
}
+ // Ask the transport for a monitor that will be used to relay log events back to it.
+ IBackupManagerMonitor monitor = null;
+ try {
+ monitor = transport.getBackupManagerMonitor();
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to retrieve monitor from transport");
+ }
+
// At this point, we have started a new journal file, and the old
// file identity is being passed to the backup processing task.
// When it completes successfully, that old journal file will be
@@ -225,7 +234,7 @@
queue,
oldJournal,
/* observer */ null,
- /* monitor */ null,
+ monitor,
listener,
Collections.emptyList(),
/* userInitiated */ false,
diff --git a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
index 237a3fa..40d7cad 100644
--- a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
@@ -18,10 +18,12 @@
import android.annotation.Nullable;
import android.app.backup.BackupTransport;
+import android.app.backup.IBackupManagerMonitor;
import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.Intent;
import android.content.pm.PackageInfo;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Slog;
@@ -363,6 +365,15 @@
}
/**
+ * See {@link IBackupTransport#getBackupManagerMonitor()}
+ */
+ public IBackupManagerMonitor getBackupManagerMonitor() throws RemoteException {
+ AndroidFuture<IBackupManagerMonitor> resultFuture = mTransportFutures.newFuture();
+ mTransportBinder.getBackupManagerMonitor(resultFuture);
+ return IBackupManagerMonitor.Stub.asInterface((IBinder) getFutureResult(resultFuture));
+ }
+
+ /**
* Allows the {@link TransportConnection} to notify this client
* if the underlying transport has become unusable. If that happens
* we want to cancel all active futures or callbacks.
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index c4f5766..a57f5a2 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -45,11 +45,11 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
index dbff628..2c5d582 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
@@ -35,12 +35,12 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index c713a41..551ffff 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -38,8 +38,6 @@
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -47,6 +45,8 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.am.DropboxRateLimiter;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 960922e..92889c0 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -40,8 +40,6 @@
import android.util.LongArrayQueue;
import android.util.MathUtils;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -49,6 +47,8 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1150b83..72876f6 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -131,8 +131,6 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -147,6 +145,8 @@
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.Installer;
import com.android.server.pm.UserManagerInternal;
import com.android.server.storage.AppFuseBridge;
diff --git a/services/core/java/com/android/server/SystemUpdateManagerService.java b/services/core/java/com/android/server/SystemUpdateManagerService.java
index fcba9b5..811a780 100644
--- a/services/core/java/com/android/server/SystemUpdateManagerService.java
+++ b/services/core/java/com/android/server/SystemUpdateManagerService.java
@@ -38,12 +38,12 @@
import android.provider.Settings;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
index 725bccf..12f2e10 100644
--- a/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
+++ b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
@@ -27,8 +27,9 @@
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
index b379b5d..3603dcd 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -29,13 +29,13 @@
import android.util.PackageUtils;
import android.util.Pair;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 04bd869..62a97dc 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -65,8 +65,6 @@
import android.util.AtomicFile;
import android.util.Base64;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.R;
@@ -75,6 +73,8 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.FgThread;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 82af12e..b166adc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13897,7 +13897,7 @@
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered + " userid=" + userId);
- if ((resultTo != null) && !ordered) {
+ if ((resultTo != null) && !ordered && !mEnableModernQueue) {
Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
}
@@ -14459,10 +14459,12 @@
filterNonExportedComponents(intent, callingUid, registeredReceivers,
mPlatformCompat, callerPackage);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
- if (!ordered && NR > 0) {
+ if (!ordered && NR > 0 && !mEnableModernQueue) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
- // components to be launched.
+ // components to be launched. We don't do this split for the modern
+ // queue because delivery to registered receivers isn't blocked
+ // behind manifest receivers.
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
@@ -16895,6 +16897,11 @@
return mSystemReady;
}
+ @Override
+ public boolean isModernQueueEnabled() {
+ return mEnableModernQueue;
+ }
+
/**
* Returns package name by pid.
*/
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index e0690bf..ba1c3b3 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -146,8 +146,6 @@
import android.util.SparseArray;
import android.util.SparseArrayMap;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -157,6 +155,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.TriConsumer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 28a81e6..4590c85 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -167,7 +167,7 @@
*/
public long DELAY_NORMAL_MILLIS = DEFAULT_DELAY_NORMAL_MILLIS;
private static final String KEY_DELAY_NORMAL_MILLIS = "bcast_delay_normal_millis";
- private static final long DEFAULT_DELAY_NORMAL_MILLIS = 1_000;
+ private static final long DEFAULT_DELAY_NORMAL_MILLIS = 0;
/**
* For {@link BroadcastQueueModernImpl}: Delay to apply to broadcasts
@@ -175,7 +175,16 @@
*/
public long DELAY_CACHED_MILLIS = DEFAULT_DELAY_CACHED_MILLIS;
private static final String KEY_DELAY_CACHED_MILLIS = "bcast_delay_cached_millis";
- private static final long DEFAULT_DELAY_CACHED_MILLIS = 10_000;
+ private static final long DEFAULT_DELAY_CACHED_MILLIS = 0;
+
+ /**
+ * For {@link BroadcastQueueModernImpl}: Delay to apply to urgent
+ * broadcasts, typically a negative value to indicate they should be
+ * executed before most other pending broadcasts.
+ */
+ public long DELAY_URGENT_MILLIS = DEFAULT_DELAY_URGENT_MILLIS;
+ private static final String KEY_DELAY_URGENT_MILLIS = "bcast_delay_urgent_millis";
+ private static final long DEFAULT_DELAY_URGENT_MILLIS = -120_000;
/**
* For {@link BroadcastQueueModernImpl}: Maximum number of complete
@@ -313,6 +322,8 @@
DEFAULT_DELAY_NORMAL_MILLIS);
DELAY_CACHED_MILLIS = getDeviceConfigLong(KEY_DELAY_CACHED_MILLIS,
DEFAULT_DELAY_CACHED_MILLIS);
+ DELAY_URGENT_MILLIS = getDeviceConfigLong(KEY_DELAY_URGENT_MILLIS,
+ DEFAULT_DELAY_URGENT_MILLIS);
MAX_HISTORY_COMPLETE_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_COMPLETE_SIZE,
DEFAULT_MAX_HISTORY_COMPLETE_SIZE);
MAX_HISTORY_SUMMARY_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_SUMMARY_SIZE,
@@ -354,6 +365,8 @@
TimeUtils.formatDuration(DELAY_NORMAL_MILLIS)).println();
pw.print(KEY_DELAY_CACHED_MILLIS,
TimeUtils.formatDuration(DELAY_CACHED_MILLIS)).println();
+ pw.print(KEY_DELAY_URGENT_MILLIS,
+ TimeUtils.formatDuration(DELAY_URGENT_MILLIS)).println();
pw.print(KEY_MAX_HISTORY_COMPLETE_SIZE, MAX_HISTORY_COMPLETE_SIZE).println();
pw.print(KEY_MAX_HISTORY_SUMMARY_SIZE, MAX_HISTORY_SUMMARY_SIZE).println();
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 868c3ae..5123517 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -668,17 +668,18 @@
return;
}
- // If we have too many broadcasts pending, bypass any delays that
- // might have been applied above to aid draining
- if (mPending.size() + mPendingUrgent.size() >= constants.MAX_PENDING_BROADCASTS) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_MAX_PENDING;
- return;
- }
-
if (mCountForeground > 0) {
- mRunnableAt = runnableAt;
+ mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
+ } else if (mCountInteractive > 0) {
+ mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
+ mRunnableAtReason = REASON_CONTAINS_INTERACTIVE;
+ } else if (mCountInstrumented > 0) {
+ mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
+ mRunnableAtReason = REASON_CONTAINS_INSTRUMENTED;
+ } else if (mProcessInstrumented) {
+ mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
+ mRunnableAtReason = REASON_INSTRUMENTED;
} else if (mCountOrdered > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_ORDERED;
@@ -688,18 +689,9 @@
} else if (mCountPrioritized > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_PRIORITIZED;
- } else if (mCountInteractive > 0) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_CONTAINS_INTERACTIVE;
} else if (mCountResultTo > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
- } else if (mCountInstrumented > 0) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_CONTAINS_INSTRUMENTED;
- } else if (mProcessInstrumented) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_INSTRUMENTED;
} else if (mProcessCached) {
mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
mRunnableAtReason = REASON_CACHED;
@@ -707,6 +699,13 @@
mRunnableAt = runnableAt + constants.DELAY_NORMAL_MILLIS;
mRunnableAtReason = REASON_NORMAL;
}
+
+ // If we have too many broadcasts pending, bypass any delays that
+ // might have been applied above to aid draining
+ if (mPending.size() + mPendingUrgent.size() >= constants.MAX_PENDING_BROADCASTS) {
+ mRunnableAt = runnableAt;
+ mRunnableAtReason = REASON_MAX_PENDING;
+ }
} else {
mRunnableAt = Long.MAX_VALUE;
mRunnableAtReason = REASON_EMPTY;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index db3ef3d..4c831bd 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -210,6 +210,12 @@
private final BroadcastConstants mFgConstants;
private final BroadcastConstants mBgConstants;
+ /**
+ * Timestamp when last {@link #testAllProcessQueues} failure was observed;
+ * used for throttling log messages.
+ */
+ private @UptimeMillisLong long mLastTestFailureTime;
+
private static final int MSG_UPDATE_RUNNING_LIST = 1;
private static final int MSG_DELIVERY_TIMEOUT_SOFT = 2;
private static final int MSG_DELIVERY_TIMEOUT_HARD = 3;
@@ -521,6 +527,8 @@
@Override
public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {
+ if (DEBUG_BROADCAST) logv("Enqueuing " + r + " for " + r.receivers.size() + " receivers");
+
r.applySingletonPolicy(mService);
final IntentFilter removeMatchingFilter = (r.options != null)
@@ -859,10 +867,11 @@
mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_HARD, queue);
}
- // Even if we have more broadcasts, if we've made reasonable progress
- // and someone else is waiting, retire ourselves to avoid starvation
- final boolean shouldRetire = (mRunnableHead != null)
- && (queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
+ // If we've made reasonable progress, periodically retire ourselves to
+ // avoid starvation of other processes and stack overflow when a
+ // broadcast is immediately finished without waiting
+ final boolean shouldRetire =
+ (queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
if (queue.isRunnable() && queue.isProcessWarm() && !shouldRetire) {
// We're on a roll; move onto the next broadcast for this process
@@ -1034,7 +1043,11 @@
BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
while (leaf != null) {
if (!test.test(leaf)) {
- logv("Test " + label + " failed due to " + leaf.toShortString(), pw);
+ final long now = SystemClock.uptimeMillis();
+ if (now > mLastTestFailureTime + DateUtils.SECOND_IN_MILLIS) {
+ mLastTestFailureTime = now;
+ logv("Test " + label + " failed due to " + leaf.toShortString(), pw);
+ }
return false;
}
leaf = leaf.processNameNext;
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index d7dc8b8..2a3c897 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -78,7 +78,7 @@
final int callingPid; // the pid of who sent this
final int callingUid; // the uid of who sent this
final boolean callerInstantApp; // caller is an Instant App?
- final boolean callerInstrumented; // caller is being instrumented
+ final boolean callerInstrumented; // caller is being instrumented?
final boolean ordered; // serialize the send to receivers?
final boolean sticky; // originated from existing sticky data?
final boolean alarm; // originated from an alarm triggering?
@@ -366,8 +366,7 @@
callingPid = _callingPid;
callingUid = _callingUid;
callerInstantApp = _callerInstantApp;
- callerInstrumented = (_callerApp != null)
- ? (_callerApp.getActiveInstrumentation() != null) : false;
+ callerInstrumented = isCallerInstrumented(_callerApp, _callingUid);
resolvedType = _resolvedType;
requiredPermissions = _requiredPermissions;
excludedPermissions = _excludedPermissions;
@@ -675,6 +674,17 @@
return (newIntent != null) ? newIntent : intent;
}
+ static boolean isCallerInstrumented(@Nullable ProcessRecord callerApp, int callingUid) {
+ switch (UserHandle.getAppId(callingUid)) {
+ case android.os.Process.ROOT_UID:
+ case android.os.Process.SHELL_UID:
+ // Broadcasts sent via "shell" are typically invoked by test
+ // suites, so we treat them as if the caller was instrumented
+ return true;
+ }
+ return (callerApp != null) ? (callerApp.getActiveInstrumentation() != null) : false;
+ }
+
/**
* Return if given receivers list has more than one traunch of priorities.
*/
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3fa41c0..3c26116 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -3327,6 +3327,14 @@
}
EventLog.writeEvent(EventLogTags.UC_SEND_USER_BROADCAST, logUserId, intent.getAction());
+ // When the modern broadcast stack is enabled, deliver all our
+ // broadcasts as unordered, since the modern stack has better
+ // support for sequencing cold-starts, and it supports delivering
+ // resultTo for non-ordered broadcasts
+ if (mService.mEnableModernQueue) {
+ ordered = false;
+ }
+
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java
index 1162498..1e68837 100644
--- a/services/core/java/com/android/server/app/GameManagerSettings.java
+++ b/services/core/java/com/android/server/app/GameManagerSettings.java
@@ -21,12 +21,12 @@
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.app.GameManagerService.GamePackageConfiguration;
import com.android.server.app.GameManagerService.GamePackageConfiguration.GameModeConfiguration;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index bc650ad..a58583c 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -131,8 +131,6 @@
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -152,6 +150,8 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index dd0c4b86..10243e2 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -53,13 +53,13 @@
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import java.io.File;
import java.io.FileInputStream;
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 2c68aaf..bd9d057 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -52,8 +52,6 @@
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -62,6 +60,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.FgThread;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cbfd17f0..f3a9a69 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4024,7 +4024,7 @@
}
}
- private void setLeAudioVolumeOnModeUpdate(int mode, int streamType, int device) {
+ private void setLeAudioVolumeOnModeUpdate(int mode, int device) {
switch (mode) {
case AudioSystem.MODE_IN_COMMUNICATION:
case AudioSystem.MODE_IN_CALL:
@@ -4038,10 +4038,16 @@
return;
}
- // Currently, DEVICE_OUT_BLE_HEADSET is the only output type for LE_AUDIO profile.
- // (See AudioDeviceBroker#createBtDeviceInfo())
- int index = mStreamStates[streamType].getIndex(AudioSystem.DEVICE_OUT_BLE_HEADSET);
- int maxIndex = mStreamStates[streamType].getMaxIndex();
+ // Forcefully set LE audio volume as a workaround, since in some cases
+ // (like the outgoing call) the value of 'device' is not DEVICE_OUT_BLE_*
+ // even when BLE is connected.
+ if (!AudioSystem.isLeAudioDeviceType(device)) {
+ device = AudioSystem.DEVICE_OUT_BLE_HEADSET;
+ }
+
+ final int streamType = getBluetoothContextualVolumeStream(mode);
+ final int index = mStreamStates[streamType].getIndex(device);
+ final int maxIndex = mStreamStates[streamType].getMaxIndex();
if (DEBUG_VOL) {
Log.d(TAG, "setLeAudioVolumeOnModeUpdate postSetLeAudioVolumeIndex index="
@@ -5427,9 +5433,7 @@
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(previousMode, mode);
- // Forcefully set LE audio volume as a workaround, since the value of 'device'
- // is not DEVICE_OUT_BLE_* even when BLE is connected.
- setLeAudioVolumeOnModeUpdate(mode, streamType, device);
+ setLeAudioVolumeOnModeUpdate(mode, device);
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
diff --git a/services/core/java/com/android/server/biometrics/log/ALSProbe.java b/services/core/java/com/android/server/biometrics/log/ALSProbe.java
index 1a5f31c..da43618 100644
--- a/services/core/java/com/android/server/biometrics/log/ALSProbe.java
+++ b/services/core/java/com/android/server/biometrics/log/ALSProbe.java
@@ -52,16 +52,13 @@
private boolean mDestroyed = false;
private boolean mDestroyRequested = false;
private boolean mDisableRequested = false;
- private volatile NextConsumer mNextConsumer = null;
+ private NextConsumer mNextConsumer = null;
private volatile float mLastAmbientLux = -1;
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
- mLastAmbientLux = event.values[0];
- if (mNextConsumer != null) {
- completeNextConsumer(mLastAmbientLux);
- }
+ onNext(event.values[0]);
}
@Override
@@ -133,11 +130,29 @@
// if a final consumer is set it will call destroy/disable on the next value if requested
if (!mDestroyed && mNextConsumer == null) {
- disable();
+ disableLightSensorLoggingLocked();
mDestroyed = true;
}
}
+ private synchronized void onNext(float value) {
+ mLastAmbientLux = value;
+
+ final NextConsumer consumer = mNextConsumer;
+ mNextConsumer = null;
+ if (consumer != null) {
+ Slog.v(TAG, "Finishing next consumer");
+
+ if (mDestroyRequested) {
+ destroy();
+ } else if (mDisableRequested) {
+ disable();
+ }
+
+ consumer.consume(value);
+ }
+ }
+
/** The most recent lux reading. */
public float getMostRecentLux() {
return mLastAmbientLux;
@@ -160,7 +175,7 @@
@Nullable Handler handler) {
final NextConsumer nextConsumer = new NextConsumer(consumer, handler);
final float current = mLastAmbientLux;
- if (current > 0) {
+ if (current > -1f) {
nextConsumer.consume(current);
} else if (mDestroyed) {
nextConsumer.consume(-1f);
@@ -172,23 +187,6 @@
}
}
- private synchronized void completeNextConsumer(float value) {
- Slog.v(TAG, "Finishing next consumer");
-
- final NextConsumer consumer = mNextConsumer;
- mNextConsumer = null;
-
- if (mDestroyRequested) {
- destroy();
- } else if (mDisableRequested) {
- disable();
- }
-
- if (consumer != null) {
- consumer.consume(value);
- }
- }
-
private void enableLightSensorLoggingLocked() {
if (!mEnabled) {
mEnabled = true;
@@ -219,9 +217,13 @@
}
}
- private void onTimeout() {
+ private synchronized void onTimeout() {
Slog.e(TAG, "Max time exceeded for ALS logger - disabling: "
+ mLightSensorListener.hashCode());
+
+ // if consumers are waiting but there was no sensor change, complete them with the latest
+ // value before disabling
+ onNext(mLastAmbientLux);
disable();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java b/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
index 49cddaa..7fb27b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
@@ -23,11 +23,11 @@
import android.os.Environment;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index a9981d0..5a82b3a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -19,10 +19,10 @@
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.face.Face;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.biometrics.sensors.BiometricUserState;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
index ae173f7..b1a9ef1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
@@ -19,10 +19,10 @@
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.fingerprint.Fingerprint;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.biometrics.sensors.BiometricUserState;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 5c679b8..9c1cf38 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -51,8 +51,6 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -60,6 +58,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IntPair;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
index 7c9a484..3581981 100644
--- a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
+++ b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
@@ -22,12 +22,12 @@
import android.os.SystemClock;
import android.os.UserManager;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 1686cb2..e9856d0 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -55,8 +55,6 @@
import android.provider.Settings;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -64,6 +62,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.RingBuffer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index a11f172..f30a84f 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -26,14 +26,14 @@
import android.util.SparseArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
index 3fecef7..88145bd 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
@@ -34,10 +34,10 @@
import android.text.FontConfig;
import android.util.IndentingPrintWriter;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.util.DumpUtils;
+import com.android.modules.utils.TypedXmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java b/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
index 15abbd5..fd00980 100644
--- a/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
+++ b/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
@@ -21,10 +21,11 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index ba19cf0..573bf19 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -25,11 +25,11 @@
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.hdmi.Constants.AbortReason;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.Constants.FeatureOpcode;
diff --git a/services/core/java/com/android/server/input/ConfigurationProcessor.java b/services/core/java/com/android/server/input/ConfigurationProcessor.java
index 0563806..b6953a3 100644
--- a/services/core/java/com/android/server/input/ConfigurationProcessor.java
+++ b/services/core/java/com/android/server/input/ConfigurationProcessor.java
@@ -18,11 +18,11 @@
import android.text.TextUtils;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
import java.io.InputStream;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index 5513cd6..1bb10c7 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -21,8 +21,6 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseIntArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Surface;
@@ -34,6 +32,9 @@
import org.xmlpull.v1.XmlPullParserException;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
index 816d08a..8e6452b 100644
--- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
+++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
@@ -25,12 +25,13 @@
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
index ab91290..e831e40 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
@@ -17,9 +17,9 @@
package com.android.server.integrity.parser;
import android.annotation.Nullable;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.integrity.model.RuleMetadata;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
index 7aed352..022b4b8 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
@@ -19,9 +19,9 @@
import static com.android.server.integrity.parser.RuleMetadataParser.RULE_PROVIDER_TAG;
import static com.android.server.integrity.parser.RuleMetadataParser.VERSION_TAG;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.integrity.model.RuleMetadata;
import org.xmlpull.v1.XmlSerializer;
diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
index 37a4869..67c931f 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
@@ -37,12 +37,12 @@
import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java b/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java
index d13b1f4..215c653 100644
--- a/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java
+++ b/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java
@@ -28,12 +28,12 @@
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
index 0c209c5..2596cee 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
@@ -45,9 +45,10 @@
import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.Base64;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
index eb34e98..9e3da23 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
@@ -46,9 +46,10 @@
import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.Base64;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlSerializer;
+
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertPath;
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 77dbde1..f653b93 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1662,116 +1662,75 @@
}
private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
- MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
-
+ MediaRoute2ProviderInfo newInfo = provider.getProviderInfo();
int providerInfoIndex =
indexOfRouteProviderInfoByUniqueId(provider.getUniqueId(), mLastProviderInfos);
-
- MediaRoute2ProviderInfo prevInfo =
+ MediaRoute2ProviderInfo oldInfo =
providerInfoIndex == -1 ? null : mLastProviderInfos.get(providerInfoIndex);
-
- // Ignore if no changes
- if (Objects.equals(prevInfo, currentInfo)) {
+ if (oldInfo == newInfo) {
+ // Nothing to do.
return;
}
- boolean hasAddedOrModifiedRoutes = false;
- boolean hasRemovedRoutes = false;
-
- boolean isSystemProvider = provider.mIsSystemRouteProvider;
-
- if (prevInfo == null) {
- // Provider is being added.
- mLastProviderInfos.add(currentInfo);
- addToRoutesMap(currentInfo.getRoutes(), isSystemProvider);
- // Check if new provider exposes routes.
- hasAddedOrModifiedRoutes = !currentInfo.getRoutes().isEmpty();
- } else if (currentInfo == null) {
- // Provider is being removed.
- hasRemovedRoutes = true;
- mLastProviderInfos.remove(prevInfo);
- removeFromRoutesMap(prevInfo.getRoutes(), isSystemProvider);
- } else {
- // Provider is being updated.
- mLastProviderInfos.set(providerInfoIndex, currentInfo);
- final Collection<MediaRoute2Info> currentRoutes = currentInfo.getRoutes();
-
- // Checking for individual routes.
- for (MediaRoute2Info route : currentRoutes) {
- if (!route.isValid()) {
- Slog.w(
- TAG,
- "onProviderStateChangedOnHandler: Ignoring invalid route : "
- + route);
- continue;
- }
-
- MediaRoute2Info prevRoute = prevInfo.getRoute(route.getOriginalId());
- if (prevRoute == null || !Objects.equals(prevRoute, route)) {
- hasAddedOrModifiedRoutes = true;
- mLastNotifiedRoutesToPrivilegedRouters.put(route.getId(), route);
- if (!isSystemProvider) {
- mLastNotifiedRoutesToNonPrivilegedRouters.put(route.getId(), route);
- }
- }
+ Collection<MediaRoute2Info> newRoutes;
+ Set<String> newRouteIds;
+ if (newInfo != null) {
+ // Adding or updating a provider.
+ newRoutes = newInfo.getRoutes();
+ newRouteIds =
+ newRoutes.stream().map(MediaRoute2Info::getId).collect(Collectors.toSet());
+ if (providerInfoIndex >= 0) {
+ mLastProviderInfos.set(providerInfoIndex, newInfo);
+ } else {
+ mLastProviderInfos.add(newInfo);
}
+ } else /* newInfo == null */ {
+ // Removing a provider.
+ mLastProviderInfos.remove(oldInfo);
+ newRouteIds = Collections.emptySet();
+ newRoutes = Collections.emptySet();
+ }
- // Checking for individual removals
- for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
- if (currentInfo.getRoute(prevRoute.getOriginalId()) == null) {
- hasRemovedRoutes = true;
- mLastNotifiedRoutesToPrivilegedRouters.remove(prevRoute.getId());
- if (!isSystemProvider) {
- mLastNotifiedRoutesToNonPrivilegedRouters.remove(prevRoute.getId());
- }
- }
+ // Add new routes to the maps.
+ boolean hasAddedOrModifiedRoutes = false;
+ for (MediaRoute2Info newRouteInfo : newRoutes) {
+ if (!newRouteInfo.isValid()) {
+ Slog.w(TAG, "onProviderStateChangedOnHandler: Ignoring invalid route : "
+ + newRouteInfo);
+ continue;
+ }
+ if (!provider.mIsSystemRouteProvider) {
+ mLastNotifiedRoutesToNonPrivilegedRouters.put(
+ newRouteInfo.getId(), newRouteInfo);
+ }
+ MediaRoute2Info oldRouteInfo =
+ mLastNotifiedRoutesToPrivilegedRouters.put(
+ newRouteInfo.getId(), newRouteInfo);
+ hasAddedOrModifiedRoutes |=
+ oldRouteInfo == null || !oldRouteInfo.equals(newRouteInfo);
+ }
+
+ // Remove stale routes from the maps.
+ Collection<MediaRoute2Info> oldRoutes =
+ oldInfo == null ? Collections.emptyList() : oldInfo.getRoutes();
+ boolean hasRemovedRoutes = false;
+ for (MediaRoute2Info oldRoute : oldRoutes) {
+ String oldRouteId = oldRoute.getId();
+ if (!newRouteIds.contains(oldRouteId)) {
+ hasRemovedRoutes = true;
+ mLastNotifiedRoutesToPrivilegedRouters.remove(oldRouteId);
+ mLastNotifiedRoutesToNonPrivilegedRouters.remove(oldRouteId);
}
}
dispatchUpdates(
hasAddedOrModifiedRoutes,
hasRemovedRoutes,
- isSystemProvider,
+ provider.mIsSystemRouteProvider,
mSystemProvider.getDefaultRoute());
}
/**
- * Adds provided routes to {@link #mLastNotifiedRoutesToPrivilegedRouters}. Also adds them
- * to {@link #mLastNotifiedRoutesToNonPrivilegedRouters} if they were provided by a
- * non-system route provider. Overwrites any route with matching id that already exists.
- *
- * @param routes list of routes to be added.
- * @param isSystemRoutes indicates whether routes come from a system route provider.
- */
- private void addToRoutesMap(
- @NonNull Collection<MediaRoute2Info> routes, boolean isSystemRoutes) {
- for (MediaRoute2Info route : routes) {
- if (!isSystemRoutes) {
- mLastNotifiedRoutesToNonPrivilegedRouters.put(route.getId(), route);
- }
- mLastNotifiedRoutesToPrivilegedRouters.put(route.getId(), route);
- }
- }
-
- /**
- * Removes provided routes from {@link #mLastNotifiedRoutesToPrivilegedRouters}. Also
- * removes them from {@link #mLastNotifiedRoutesToNonPrivilegedRouters} if they were
- * provided by a non-system route provider.
- *
- * @param routes list of routes to be removed.
- * @param isSystemRoutes whether routes come from a system route provider.
- */
- private void removeFromRoutesMap(
- @NonNull Collection<MediaRoute2Info> routes, boolean isSystemRoutes) {
- for (MediaRoute2Info route : routes) {
- if (!isSystemRoutes) {
- mLastNotifiedRoutesToNonPrivilegedRouters.remove(route.getId());
- }
- mLastNotifiedRoutesToPrivilegedRouters.remove(route.getId());
- }
- }
-
- /**
* Dispatches the latest route updates in {@link #mLastNotifiedRoutesToPrivilegedRouters}
* and {@link #mLastNotifiedRoutesToNonPrivilegedRouters} to registered {@link
* android.media.MediaRouter2 routers} and {@link MediaRouter2Manager managers} after a call
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index d770f71..56f3296 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -239,8 +239,6 @@
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.SparseSetArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.R;
@@ -255,6 +253,8 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.StatLogger;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.NetworkIdentityUtils;
import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index 4506b7d..7da78f3 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -20,14 +20,14 @@
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.HexDump;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 3238f1f..3329f54 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -36,10 +36,10 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
-import android.util.TypedXmlSerializer;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import java.io.IOException;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 4d55d4e..004caf3 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -60,14 +60,14 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import com.android.server.utils.TimingsTraceAndSlog;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f459c0e..eb37ceb 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -258,8 +258,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.StatsEvent;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.view.accessibility.AccessibilityEvent;
@@ -291,6 +289,8 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
import com.android.internal.widget.LockPatternUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.IoThread;
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index d8aa469..bbbf452 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -63,8 +63,6 @@
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.StatsEvent;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -73,6 +71,8 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.notification.PermissionHelper.PackagePermission;
import org.json.JSONArray;
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 61936df..4bbd40d 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -30,12 +30,12 @@
import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.PackageManagerService;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 4c23ab8..4b2c88c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -72,8 +72,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsEvent;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -82,6 +80,8 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 9e39226..eae614a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -28,14 +28,14 @@
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index bb918d5..5e98cc0 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -35,9 +35,10 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.TypedValue;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 4e9c472..d6233c7 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -148,9 +148,18 @@
+ intent.toShortString(false, true, false, false)
+ " " + intent.getExtras(), here);
}
+ final boolean ordered;
+ if (mAmInternal.isModernQueueEnabled()) {
+ // When the modern broadcast stack is enabled, deliver all our
+ // broadcasts as unordered, since the modern stack has better
+ // support for sequencing cold-starts, and it supports
+ // delivering resultTo for non-ordered broadcasts
+ ordered = false;
+ } else {
+ ordered = (finishedReceiver != null);
+ }
mAmInternal.broadcastIntent(
- intent, finishedReceiver, requiredPermissions,
- finishedReceiver != null, userId,
+ intent, finishedReceiver, requiredPermissions, ordered, userId,
broadcastAllowList == null ? null : broadcastAllowList.get(userId),
filterExtrasForReceiver, bOptions);
}
diff --git a/services/core/java/com/android/server/pm/CommitRequest.java b/services/core/java/com/android/server/pm/CommitRequest.java
deleted file mode 100644
index d1a6002..0000000
--- a/services/core/java/com/android/server/pm/CommitRequest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.annotation.NonNull;
-
-import java.util.Map;
-
-/**
- * Package state to commit to memory and disk after reconciliation has completed.
- */
-final class CommitRequest {
- final Map<String, ReconciledPackage> mReconciledPackages;
- @NonNull final int[] mAllUsers;
-
- CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
- @NonNull int[] allUsers) {
- mReconciledPackages = reconciledPackages;
- mAllUsers = allUsers;
- }
-}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 86b8272..b9967f9 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -114,7 +114,6 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -123,6 +122,7 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.PackageInfoUtils;
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
index 718756f..0cd698a 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
@@ -21,10 +21,10 @@
import android.content.IntentFilter;
import android.os.UserHandle;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.utils.SnapshotCache;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index f6472a7..6f59096 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -352,8 +352,7 @@
}
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- private void scanDirTracedLI(File scanDir,
- int parseFlags, int scanFlags,
+ private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,
PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 30ecc1c..9d007c9 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -245,50 +245,42 @@
@GuardedBy("mPm.mLock")
public AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
- final ScanResult result = reconciledPkg.mScanResult;
- final ScanRequest request = result.mRequest;
+ final InstallRequest request = reconciledPkg.mInstallRequest;
// TODO(b/135203078): Move this even further away
- ParsedPackage parsedPackage = request.mParsedPackage;
- if ("android".equals(parsedPackage.getPackageName())) {
+ ParsedPackage parsedPackage = request.getParsedPackage();
+ if (parsedPackage != null && "android".equals(parsedPackage.getPackageName())) {
// TODO(b/135203078): Move this to initial parse
parsedPackage.setVersionCode(mPm.getSdkVersion())
.setVersionCodeMajor(0);
}
- final AndroidPackage oldPkg = request.mOldPkg;
- final @ParsingPackageUtils.ParseFlags int parseFlags = request.mParseFlags;
- final @PackageManagerService.ScanFlags int scanFlags = request.mScanFlags;
- final PackageSetting oldPkgSetting = request.mOldPkgSetting;
- final PackageSetting originalPkgSetting = request.mOriginalPkgSetting;
- final UserHandle user = request.mUser;
- final String realPkgName = request.mRealPkgName;
- final List<String> changedAbiCodePath = result.mChangedAbiCodePath;
+ final @PackageManagerService.ScanFlags int scanFlags = request.getScanFlags();
+ final PackageSetting oldPkgSetting = request.getScanRequestOldPackageSetting();
+ final PackageSetting originalPkgSetting = request.getScanRequestOriginalPackageSetting();
+ final String realPkgName = request.getRealPackageName();
+ final List<String> changedAbiCodePath = request.getChangedAbiCodePath();
final PackageSetting pkgSetting;
- if (request.mPkgSetting != null) {
+ if (request.getScanRequestPackageSetting() != null) {
SharedUserSetting requestSharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(
- request.mPkgSetting);
+ request.getScanRequestPackageSetting());
SharedUserSetting resultSharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(
- result.mPkgSetting);
+ request.getScanRequestPackageSetting());
if (requestSharedUserSetting != null
&& requestSharedUserSetting != resultSharedUserSetting) {
// shared user changed, remove from old shared user
- requestSharedUserSetting.removePackage(request.mPkgSetting);
+ requestSharedUserSetting.removePackage(request.getScanRequestPackageSetting());
// Prune unused SharedUserSetting
if (mPm.mSettings.checkAndPruneSharedUserLPw(requestSharedUserSetting, false)) {
// Set the app ID in removed info for UID_REMOVED broadcasts
- if (reconciledPkg.mInstallRequest != null
- && reconciledPkg.mInstallRequest.getRemovedInfo() != null) {
- reconciledPkg.mInstallRequest.getRemovedInfo().mRemovedAppId =
- requestSharedUserSetting.mAppId;
- }
+ request.setRemovedAppId(requestSharedUserSetting.mAppId);
}
}
}
- if (result.mExistingSettingCopied) {
- pkgSetting = request.mPkgSetting;
- pkgSetting.updateFrom(result.mPkgSetting);
+ if (request.isExistingSettingCopied()) {
+ pkgSetting = request.getScanRequestPackageSetting();
+ pkgSetting.updateFrom(request.getScannedPackageSetting());
} else {
- pkgSetting = result.mPkgSetting;
+ pkgSetting = request.getScannedPackageSetting();
if (originalPkgSetting != null) {
mPm.mSettings.addRenamedPackageLPw(
AndroidPackageUtils.getRealPackageOrNull(parsedPackage),
@@ -308,26 +300,23 @@
mPm.mSettings.convertSharedUserSettingsLPw(sharedUserSetting);
}
}
- if (reconciledPkg.mInstallRequest != null
- && reconciledPkg.mInstallRequest.isForceQueryableOverride()) {
+ if (request.isForceQueryableOverride()) {
pkgSetting.setForceQueryableOverride(true);
}
// If this is part of a standard install, set the initiating package name, else rely on
// previous device state.
- if (reconciledPkg.mInstallRequest != null) {
- InstallSource installSource = reconciledPkg.mInstallRequest.getInstallSource();
- if (installSource != null) {
- if (installSource.initiatingPackageName != null) {
- final PackageSetting ips = mPm.mSettings.getPackageLPr(
- installSource.initiatingPackageName);
- if (ips != null) {
- installSource = installSource.setInitiatingPackageSignatures(
- ips.getSignatures());
- }
+ InstallSource installSource = request.getInstallSource();
+ if (installSource != null) {
+ if (installSource.initiatingPackageName != null) {
+ final PackageSetting ips = mPm.mSettings.getPackageLPr(
+ installSource.initiatingPackageName);
+ if (ips != null) {
+ installSource = installSource.setInitiatingPackageSignatures(
+ ips.getSignatures());
}
- pkgSetting.setInstallSource(installSource);
}
+ pkgSetting.setInstallSource(installSource);
}
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -382,10 +371,9 @@
}
}
- final int userId = user == null ? 0 : user.getIdentifier();
+ final int userId = request.getUserId();
// Modify state for the given package setting
- commitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags,
- (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
+ commitPackageSettings(pkg, pkgSetting, oldPkgSetting, reconciledPkg);
if (pkgSetting.getInstantApp(userId)) {
mPm.mInstantAppRegistry.addInstantApp(userId, pkgSetting.getAppId());
}
@@ -401,11 +389,14 @@
* Adds a scanned package to the system. When this method is finished, the package will
* be available for query, resolution, etc...
*/
- private void commitPackageSettings(@NonNull AndroidPackage pkg, @Nullable AndroidPackage oldPkg,
+ private void commitPackageSettings(@NonNull AndroidPackage pkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
- final @PackageManagerService.ScanFlags int scanFlags, boolean chatty,
ReconciledPackage reconciledPkg) {
final String pkgName = pkg.getPackageName();
+ final InstallRequest request = reconciledPkg.mInstallRequest;
+ final AndroidPackage oldPkg = request.getScanRequestOldPackage();
+ final int scanFlags = request.getScanFlags();
+ final boolean chatty = (request.getParseFlags() & ParsingPackageUtils.PARSE_CHATTY) != 0;
if (mPm.mCustomResolverComponentName != null
&& mPm.mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
mPm.setUpCustomResolverActivity(pkg, pkgSetting);
@@ -421,9 +412,7 @@
reconciledPkg.mAllowedSharedLibraryInfos,
reconciledPkg.getCombinedAvailablePackages(), scanFlags);
- if (reconciledPkg.mInstallRequest != null) {
- reconciledPkg.mInstallRequest.setLibraryConsumers(clientLibPkgs);
- }
+ request.setLibraryConsumers(clientLibPkgs);
if ((scanFlags & SCAN_BOOTING) != 0) {
// No apps can run during boot scan, so they don't need to be frozen
@@ -438,8 +427,7 @@
mPm.snapshotComputer().checkPackageFrozen(pkgName);
}
- final boolean isReplace =
- reconciledPkg.mPrepareResult != null && reconciledPkg.mPrepareResult.mReplace;
+ final boolean isReplace = request.isReplace();
// Also need to kill any apps that are dependent on the library, except the case of
// installation of new version static shared library.
if (clientLibPkgs != null) {
@@ -705,6 +693,9 @@
* Returns whether the restore successfully completed.
*/
private boolean performBackupManagerRestore(int userId, int token, InstallRequest request) {
+ if (request.getPkg() == null) {
+ return false;
+ }
IBackupManager iBackupManager = mInjector.getIBackupManager();
if (iBackupManager != null) {
// For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
@@ -743,6 +734,9 @@
* Returns whether the restore successfully completed.
*/
private boolean performRollbackManagerRestore(int userId, int token, InstallRequest request) {
+ if (request.getPkg() == null) {
+ return false;
+ }
final String packageName = request.getPkg().getPackageName();
final int[] allUsers = mPm.mUserManager.getUserIds();
final int[] installedUsers;
@@ -810,22 +804,16 @@
*/
@GuardedBy("mPm.mInstallLock")
private void installPackagesLI(List<InstallRequest> requests) {
- final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
- final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
- final Map<String, InstallRequest> installRequests = new ArrayMap<>(requests.size());
+ final Set<String> scannedPackages = new ArraySet<>(requests.size());
final Map<String, Settings.VersionInfo> versionInfos = new ArrayMap<>(requests.size());
final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
boolean success = false;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
- // TODO(b/109941548): remove this once we've pulled everything from it and into
- // scan, reconcile or commit.
- final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
- prepareResult =
- preparePackageLI(request);
+ preparePackageLI(request);
} catch (PrepareFailure prepareFailure) {
request.setError(prepareFailure.error,
prepareFailure.getMessage());
@@ -835,28 +823,31 @@
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- request.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- request.setInstallerPackageName(request.getSourceInstallerPackageName());
- final String packageName = prepareResult.mPackageToScan.getPackageName();
- prepareResults.put(packageName, prepareResult);
- installRequests.put(packageName, request);
+ final ParsedPackage packageToScan = request.getParsedPackage();
+ if (packageToScan == null) {
+ request.setError(INSTALL_FAILED_SESSION_INVALID,
+ "Failed to obtain package to scan");
+ return;
+ }
+ request.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ final String packageName = packageToScan.getPackageName();
try {
- final ScanResult result = scanPackageTracedLI(
- prepareResult.mPackageToScan, prepareResult.mParseFlags,
- prepareResult.mScanFlags, System.currentTimeMillis(),
- request.getUser(), request.getAbiOverride());
- if (null != preparedScans.put(result.mPkgSetting.getPkg().getPackageName(),
- result)) {
+ final ScanResult scanResult = scanPackageTracedLI(request.getParsedPackage(),
+ request.getParseFlags(), request.getScanFlags(),
+ System.currentTimeMillis(), request.getUser(),
+ request.getAbiOverride());
+ request.setScanResult(scanResult);
+ if (!scannedPackages.add(packageName)) {
request.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package "
- + result.mPkgSetting.getPkg().getPackageName()
+ + packageName
+ " in multi-package install request.");
return;
}
if (!checkNoAppStorageIsConsistent(
- result.mRequest.mOldPkg, result.mPkgSetting.getPkg())) {
+ request.getScanRequestOldPackage(), packageToScan)) {
// TODO: INSTALL_FAILED_UPDATE_INCOMPATIBLE is about incomptabible
// signatures. Is there a better error code?
request.setError(
@@ -865,31 +856,28 @@
+ PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
return;
}
- final boolean isApex = (result.mRequest.mScanFlags & SCAN_AS_APEX) != 0;
+ final boolean isApex = (request.getScanFlags() & SCAN_AS_APEX) != 0;
if (!isApex) {
- createdAppId.put(packageName, optimisticallyRegisterAppId(result));
+ createdAppId.put(packageName, optimisticallyRegisterAppId(request));
} else {
- result.mPkgSetting.setAppId(Process.INVALID_UID);
+ request.getScannedPackageSetting().setAppId(Process.INVALID_UID);
}
- versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
- mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
+ versionInfos.put(packageName,
+ mPm.getSettingsVersionForPackage(packageToScan));
} catch (PackageManagerException e) {
request.setError("Scanning Failed.", e);
return;
}
}
- CommitRequest commitRequest;
+ Map<String, ReconciledPackage> reconciledPackages;
synchronized (mPm.mLock) {
- ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans,
- installRequests, prepareResults,
- Collections.unmodifiableMap(mPm.mPackages), versionInfos);
- Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = ReconcilePackageUtils.reconcilePackages(
- reconcileRequest, mSharedLibraries,
- mPm.mSettings.getKeySetManagerService(), mPm.mSettings);
+ requests, Collections.unmodifiableMap(mPm.mPackages),
+ versionInfos, mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
+ mPm.mSettings);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.setError("Reconciliation failed...", e);
@@ -900,15 +888,13 @@
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
- commitRequest = new CommitRequest(reconciledPackages,
- mPm.mUserManager.getUserIds());
- commitPackagesLocked(commitRequest);
+ commitPackagesLocked(reconciledPackages, mPm.mUserManager.getUserIds());
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- executePostCommitStepsLIF(commitRequest);
+ executePostCommitStepsLIF(reconciledPackages);
} finally {
if (success) {
for (InstallRequest request : requests) {
@@ -932,10 +918,10 @@
request.getDataLoaderType(), request.getUser(), mContext);
}
} else {
- for (ScanResult result : preparedScans.values()) {
- if (createdAppId.getOrDefault(result.mRequest.mParsedPackage.getPackageName(),
- false)) {
- cleanUpAppIdCreation(result);
+ for (InstallRequest installRequest : requests) {
+ if (installRequest.getParsedPackage() != null && createdAppId.getOrDefault(
+ installRequest.getParsedPackage().getPackageName(), false)) {
+ cleanUpAppIdCreation(installRequest);
}
}
// TODO(b/194319951): create a more descriptive reason than unknown
@@ -968,8 +954,7 @@
}
@GuardedBy("mPm.mInstallLock")
- private PrepareResult preparePackageLI(InstallRequest request)
- throws PrepareFailure {
+ private void preparePackageLI(InstallRequest request) throws PrepareFailure {
final int installFlags = request.getInstallFlags();
final boolean onExternal = request.getVolumeUuid() != null;
final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
@@ -1550,8 +1535,7 @@
// don't allow an upgrade from full to ephemeral
if (isInstantApp) {
- if (request.getUser() == null
- || request.getUserId() == UserHandle.USER_ALL) {
+ if (request.getUserId() == UserHandle.USER_ALL) {
for (int currentUser : allUsers) {
if (!ps.getInstantApp(currentUser)) {
// can't downgrade from full to instant
@@ -1624,7 +1608,6 @@
targetParseFlags = systemParseFlags;
targetScanFlags = systemScanFlags;
} else { // non system replace
- replace = true;
if (DEBUG_INSTALL) {
Slog.d(TAG,
"replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
@@ -1634,7 +1617,6 @@
} else { // new package install
ps = null;
disabledPs = null;
- replace = false;
oldPackage = null;
// Remember this for later, in case we need to rollback this install
String pkgName1 = parsedPackage.getPackageName();
@@ -1665,7 +1647,7 @@
// we're passing the freezer back to be closed in a later phase of install
shouldCloseFreezerBeforeReturn = false;
- return new PrepareResult(replace, targetScanFlags, targetParseFlags,
+ request.setPrepareResult(replace, targetScanFlags, targetParseFlags,
oldPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
ps, disabledPs);
} finally {
@@ -1894,19 +1876,18 @@
}
@GuardedBy("mPm.mLock")
- private void commitPackagesLocked(final CommitRequest request) {
+ private void commitPackagesLocked(Map<String, ReconciledPackage> reconciledPackages,
+ @NonNull int[] allUsers) {
// TODO: remove any expected failures from this method; this should only be able to fail due
// to unavoidable errors (I/O, etc.)
- for (ReconciledPackage reconciledPkg : request.mReconciledPackages.values()) {
- final ScanResult scanResult = reconciledPkg.mScanResult;
- final ScanRequest scanRequest = scanResult.mRequest;
- final ParsedPackage parsedPackage = scanRequest.mParsedPackage;
- final String packageName = parsedPackage.getPackageName();
+ for (ReconciledPackage reconciledPkg : reconciledPackages.values()) {
final InstallRequest installRequest = reconciledPkg.mInstallRequest;
+ final ParsedPackage parsedPackage = installRequest.getParsedPackage();
+ final String packageName = parsedPackage.getPackageName();
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
final DeletePackageHelper deletePackageHelper = new DeletePackageHelper(mPm);
- if (reconciledPkg.mPrepareResult.mReplace) {
+ if (installRequest.isReplace()) {
AndroidPackage oldPackage = mPm.mPackages.get(packageName);
// Set the update and install times
@@ -1914,15 +1895,16 @@
.getPackageStateInternal(oldPackage.getPackageName());
// TODO(b/225756739): For rebootless APEX, consider using lastUpdateMillis provided
// by apexd to be more accurate.
- reconciledPkg.mPkgSetting
- .setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
- .setLastUpdateTime(System.currentTimeMillis());
+ installRequest.setScannedPackageSettingFirstInstallTimeFromReplaced(
+ deletedPkgSetting, allUsers);
+ installRequest.setScannedPackageSettingLastUpdateTime(
+ System.currentTimeMillis());
installRequest.getRemovedInfo().mBroadcastAllowList =
mPm.mAppsFilter.getVisibilityAllowList(mPm.snapshotComputer(),
- reconciledPkg.mPkgSetting, request.mAllUsers,
- mPm.mSettings.getPackagesLocked());
- if (reconciledPkg.mPrepareResult.mSystem) {
+ installRequest.getScannedPackageSetting(),
+ allUsers, mPm.mSettings.getPackagesLocked());
+ if (installRequest.isSystem()) {
// Remove existing system package
removePackageHelper.removePackage(oldPackage, true);
if (!disableSystemPackageLPw(oldPackage)) {
@@ -1942,7 +1924,7 @@
// Settings will be written during the call to updateSettingsLI().
deletePackageHelper.executeDeletePackage(
reconciledPkg.mDeletePackageAction, packageName,
- true, request.mAllUsers, false);
+ true, allUsers, false);
} catch (SystemDeleteException e) {
if (mPm.mIsEngBuild) {
throw new RuntimeException("Unexpected failure", e);
@@ -1952,7 +1934,7 @@
// Successfully deleted the old package; proceed with replace.
// Update the in-memory copy of the previous code paths.
PackageSetting ps1 = mPm.mSettings.getPackageLPr(
- reconciledPkg.mPrepareResult.mExistingPackage.getPackageName());
+ installRequest.getExistingPackageName());
if ((installRequest.getInstallFlags() & PackageManager.DONT_KILL_APP)
== 0) {
Set<String> oldCodePaths = ps1.getOldCodePaths();
@@ -1977,9 +1959,8 @@
}
}
- AndroidPackage pkg = commitReconciledScanResultLocked(
- reconciledPkg, request.mAllUsers);
- updateSettingsLI(pkg, reconciledPkg, request.mAllUsers, installRequest);
+ AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, allUsers);
+ updateSettingsLI(pkg, allUsers, installRequest);
final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
if (ps != null) {
@@ -2000,12 +1981,12 @@
return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
}
- private void updateSettingsLI(AndroidPackage newPackage, ReconciledPackage reconciledPkg,
+ private void updateSettingsLI(AndroidPackage newPackage,
int[] allUsers, InstallRequest installRequest) {
- updateSettingsInternalLI(newPackage, reconciledPkg, allUsers, installRequest);
+ updateSettingsInternalLI(newPackage, allUsers, installRequest);
}
- private void updateSettingsInternalLI(AndroidPackage pkg, ReconciledPackage reconciledPkg,
+ private void updateSettingsInternalLI(AndroidPackage pkg,
int[] allUsers, InstallRequest installRequest) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
@@ -2175,8 +2156,7 @@
}
final int autoRevokePermissionsMode = installRequest.getAutoRevokePermissionsMode();
permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
- final ScanResult scanResult = reconciledPkg.mScanResult;
- mPm.mPermissionManager.onPackageInstalled(pkg, scanResult.mPreviousAppId,
+ mPm.mPermissionManager.onPackageInstalled(pkg, installRequest.getPreviousAppId(),
permissionParamsBuilder.build(), userId);
// Apply restricted settings on potentially dangerous packages.
if (installRequest.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
@@ -2216,14 +2196,13 @@
* locks on {@link com.android.server.pm.PackageManagerService.mLock}.
*/
@GuardedBy("mPm.mInstallLock")
- private void executePostCommitStepsLIF(CommitRequest commitRequest) {
+ private void executePostCommitStepsLIF(Map<String, ReconciledPackage> reconciledPackages) {
final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
- for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) {
- final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags
- & SCAN_AS_INSTANT_APP) != 0);
- final boolean isApex = ((reconciledPkg.mScanResult.mRequest.mScanFlags
- & SCAN_AS_APEX) != 0);
- final AndroidPackage pkg = reconciledPkg.mPkgSetting.getPkg();
+ for (ReconciledPackage reconciledPkg : reconciledPackages.values()) {
+ final InstallRequest installRequest = reconciledPkg.mInstallRequest;
+ final boolean instantApp = ((installRequest.getScanFlags() & SCAN_AS_INSTANT_APP) != 0);
+ final boolean isApex = ((installRequest.getScanFlags() & SCAN_AS_APEX) != 0);
+ final AndroidPackage pkg = installRequest.getScannedPackageSetting().getPkg();
final String packageName = pkg.getPackageName();
final String codePath = pkg.getPath();
final boolean onIncremental = mIncrementalManager != null
@@ -2238,12 +2217,12 @@
}
// Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
mAppDataHelper.prepareAppDataPostCommitLIF(pkg, 0);
- if (reconciledPkg.mPrepareResult.mClearCodeCache) {
+ if (installRequest.isClearCodeCache()) {
mAppDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
- if (reconciledPkg.mPrepareResult.mReplace) {
+ if (installRequest.isReplace()) {
mDexManager.notifyPackageUpdated(pkg.getPackageName(),
pkg.getBaseApkPath(), pkg.getSplitCodePaths());
}
@@ -2252,14 +2231,13 @@
// This needs to be done before invoking dexopt so that any install-time profile
// can be used for optimizations.
mArtManagerService.prepareAppProfiles(
- pkg,
- mPm.resolveUserIds(reconciledPkg.mInstallRequest.getUserId()),
+ pkg, mPm.resolveUserIds(installRequest.getUserId()),
/* updateReferenceProfileContent= */ true);
// Compute the compilation reason from the installation scenario.
final int compilationReason =
mDexManager.getCompilationReasonForInstallScenario(
- reconciledPkg.mInstallRequest.getInstallScenario());
+ installRequest.getInstallScenario());
// Construct the DexoptOptions early to see if we should skip running dexopt.
//
@@ -2268,10 +2246,8 @@
//
// Also, don't fail application installs if the dexopt step fails.
final boolean isBackupOrRestore =
- reconciledPkg.mInstallRequest.getInstallReason()
- == INSTALL_REASON_DEVICE_RESTORE
- || reconciledPkg.mInstallRequest.getInstallReason()
- == INSTALL_REASON_DEVICE_SETUP;
+ installRequest.getInstallReason() == INSTALL_REASON_DEVICE_RESTORE
+ || installRequest.getInstallReason() == INSTALL_REASON_DEVICE_SETUP;
final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE
@@ -2323,22 +2299,14 @@
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- ScanResult result = reconciledPkg.mScanResult;
// This mirrors logic from commitReconciledScanResultLocked, where the library files
// needed for dexopt are assigned.
- // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
- // setting needs to be passed to have a comparison, hide it behind an immutable
- // interface. There's no good reason to have 3 different ways to access the real
- // PackageSetting object, only one of which is actually correct.
- PackageSetting realPkgSetting = result.mExistingSettingCopied
- ? result.mRequest.mPkgSetting : result.mPkgSetting;
- if (realPkgSetting == null) {
- realPkgSetting = reconciledPkg.mPkgSetting;
- }
+ PackageSetting realPkgSetting = installRequest.getRealPackageSetting();
// Unfortunately, the updated system app flag is only tracked on this PackageSetting
- boolean isUpdatedSystemApp = reconciledPkg.mPkgSetting.getPkgState()
+ boolean isUpdatedSystemApp =
+ installRequest.getScannedPackageSetting().getPkgState()
.isUpdatedSystemApp();
realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
@@ -3059,7 +3027,7 @@
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
removePackageHelper.removePackage(stubPkg, true /*chatty*/);
try {
- return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
+ return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
@@ -3191,7 +3159,7 @@
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
final AndroidPackage pkg = scanSystemPackageTracedLI(
- codePath, parseFlags, scanFlags, null);
+ codePath, parseFlags, scanFlags);
synchronized (mPm.mLock) {
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3371,7 +3339,7 @@
try {
final File codePath = new File(pkg.getPath());
synchronized (mPm.mInstallLock) {
- scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
+ scanSystemPackageTracedLI(codePath, 0, scanFlags);
}
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -3521,7 +3489,7 @@
}
try {
addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
- null);
+ new UserHandle(UserHandle.USER_SYSTEM));
} catch (PackageManagerException e) {
errorCode = e.error;
errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
@@ -3584,7 +3552,7 @@
try {
synchronized (mPm.mInstallLock) {
final AndroidPackage newPkg = scanSystemPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, null);
+ scanFile, reparseFlags, rescanFlags);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
@@ -3603,10 +3571,10 @@
*/
@GuardedBy("mPm.mInstallLock")
public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
- int scanFlags, UserHandle user) throws PackageManagerException {
+ int scanFlags) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
- return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
+ return scanSystemPackageLI(scanFile, parseFlags, scanFlags);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3617,8 +3585,8 @@
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
@GuardedBy("mPm.mInstallLock")
- private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
- UserHandle user) throws PackageManagerException {
+ private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags)
+ throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3634,7 +3602,8 @@
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags,
+ new UserHandle(UserHandle.USER_SYSTEM));
}
/**
@@ -3660,33 +3629,32 @@
parsedPackage, parseFlags, scanFlags, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
- if (scanResult.mSuccess) {
- synchronized (mPm.mLock) {
- boolean appIdCreated = false;
- try {
- final String pkgName = scanResult.mPkgSetting.getPackageName();
- final ReconcileRequest reconcileRequest = new ReconcileRequest(
- Collections.singletonMap(pkgName, scanResult),
- mPm.mPackages,
- Collections.singletonMap(pkgName,
- mPm.getSettingsVersionForPackage(parsedPackage)));
- final Map<String, ReconciledPackage> reconcileResult =
- ReconcilePackageUtils.reconcilePackages(reconcileRequest,
- mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
- mPm.mSettings);
- if ((scanFlags & SCAN_AS_APEX) == 0) {
- appIdCreated = optimisticallyRegisterAppId(scanResult);
- } else {
- scanResult.mPkgSetting.setAppId(Process.INVALID_UID);
- }
- commitReconciledScanResultLocked(reconcileResult.get(pkgName),
- mPm.mUserManager.getUserIds());
- } catch (PackageManagerException e) {
- if (appIdCreated) {
- cleanUpAppIdCreation(scanResult);
- }
- throw e;
+ final InstallRequest installRequest = new InstallRequest(
+ parsedPackage, parseFlags, scanFlags, user, scanResult);
+
+ synchronized (mPm.mLock) {
+ boolean appIdCreated = false;
+ try {
+ final String pkgName = scanResult.mPkgSetting.getPackageName();
+ final Map<String, ReconciledPackage> reconcileResult =
+ ReconcilePackageUtils.reconcilePackages(
+ Collections.singletonList(installRequest),
+ mPm.mPackages, Collections.singletonMap(pkgName,
+ mPm.getSettingsVersionForPackage(parsedPackage)),
+ mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
+ mPm.mSettings);
+ if ((scanFlags & SCAN_AS_APEX) == 0) {
+ appIdCreated = optimisticallyRegisterAppId(installRequest);
+ } else {
+ installRequest.setScannedPackageSettingAppId(Process.INVALID_UID);
}
+ commitReconciledScanResultLocked(reconcileResult.get(pkgName),
+ mPm.mUserManager.getUserIds());
+ } catch (PackageManagerException e) {
+ if (appIdCreated) {
+ cleanUpAppIdCreation(installRequest);
+ }
+ throw e;
}
}
@@ -3711,13 +3679,14 @@
* @return {@code true} if a new app ID was registered and will need to be cleaned up on
* failure.
*/
- private boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
+ private boolean optimisticallyRegisterAppId(@NonNull InstallRequest installRequest)
throws PackageManagerException {
- if (!result.mExistingSettingCopied || result.needsNewAppId()) {
+ if (!installRequest.isExistingSettingCopied() || installRequest.needsNewAppId()) {
synchronized (mPm.mLock) {
// THROWS: when we can't allocate a user id. add call to check if there's
// enough space to ensure we won't throw; otherwise, don't modify state
- return mPm.mSettings.registerAppIdLPw(result.mPkgSetting, result.needsNewAppId());
+ return mPm.mSettings.registerAppIdLPw(installRequest.getScannedPackageSetting(),
+ installRequest.needsNewAppId());
}
}
return false;
@@ -3725,15 +3694,16 @@
/**
* Reverts any app ID creation that were made by
- * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the
+ * {@link #optimisticallyRegisterAppId(InstallRequest)}. Note: this is only necessary if the
* referenced method returned true.
*/
- private void cleanUpAppIdCreation(@NonNull ScanResult result) {
+ private void cleanUpAppIdCreation(@NonNull InstallRequest installRequest) {
// iff we've acquired an app ID for a new package setting, remove it so that it can be
// acquired by another request.
- if (result.mPkgSetting.getAppId() > 0) {
+ if (installRequest.getScannedPackageSetting() != null
+ && installRequest.getScannedPackageSetting().getAppId() > 0) {
synchronized (mPm.mLock) {
- mPm.mSettings.removeAppIdLPw(result.mPkgSetting.getAppId());
+ mPm.mSettings.removeAppIdLPw(installRequest.getScannedPackageSetting().getAppId());
}
}
}
@@ -3857,7 +3827,6 @@
}
}
- @GuardedBy("mPm.mInstallLock")
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags,
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 36bbf41..573082a 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
+import static android.os.Process.INVALID_UID;
import static com.android.server.pm.PackageManagerService.TAG;
@@ -29,13 +30,19 @@
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.net.Uri;
+import android.os.Build;
+import android.os.Process;
import android.os.UserHandle;
import android.util.ExceptionUtils;
import android.util.Slog;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.util.ArrayList;
@@ -45,13 +52,59 @@
private final int mUserId;
@Nullable
private final InstallArgs mInstallArgs;
- @NonNull
- private final PackageInstalledInfo mInstalledInfo;
@Nullable
private Runnable mPostInstallRunnable;
@Nullable
private PackageRemovedInfo mRemovedInfo;
+ private @PackageManagerService.ScanFlags int mScanFlags;
+ private @ParsingPackageUtils.ParseFlags int mParseFlags;
+ private boolean mReplace;
+
+ @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
+ private AndroidPackage mExistingPackage;
+ /** parsed package to be scanned */
+ @Nullable
+ private ParsedPackage mParsedPackage;
+ private boolean mClearCodeCache;
+ private boolean mSystem;
+ @Nullable
+ private PackageSetting mOriginalPs;
+ @Nullable
+ private PackageSetting mDisabledPs;
+
+ /** Package Installed Info */
+ @Nullable
+ private String mName;
+ private int mUid = -1;
+ // The set of users that originally had this package installed.
+ @Nullable
+ private int[] mOrigUsers;
+ // The set of users that now have this package installed.
+ @Nullable
+ private int[] mNewUsers;
+ @Nullable
+ private AndroidPackage mPkg;
+ private int mReturnCode;
+ @Nullable
+ private String mReturnMsg;
+ // The set of packages consuming this shared library or null if no consumers exist.
+ @Nullable
+ private ArrayList<AndroidPackage> mLibraryConsumers;
+ @Nullable
+ private PackageFreezer mFreezer;
+ /** The package this package replaces */
+ @Nullable
+ private String mOrigPackage;
+ @Nullable
+ private String mOrigPermission;
+ // The ApexInfo returned by ApexManager#installPackage, used by rebootless APEX install
+ @Nullable
+ private ApexInfo mApexInfo;
+
+ @Nullable
+ private ScanResult mScanResult;
+
// New install
InstallRequest(InstallingSession params) {
mUserId = params.getUser().getIdentifier();
@@ -63,7 +116,6 @@
params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
params.mDataLoaderType, params.mPackageSource);
- mInstalledInfo = new PackageInstalledInfo();
}
// Install existing package as user
@@ -71,56 +123,56 @@
Runnable runnable) {
mUserId = userId;
mInstallArgs = null;
- mInstalledInfo = new PackageInstalledInfo();
- mInstalledInfo.mReturnCode = returnCode;
- mInstalledInfo.mPkg = pkg;
- mInstalledInfo.mNewUsers = newUsers;
+ mReturnCode = returnCode;
+ mPkg = pkg;
+ mNewUsers = newUsers;
mPostInstallRunnable = runnable;
}
- private static class PackageInstalledInfo {
- String mName;
- int mUid = -1;
- // The set of users that originally had this package installed.
- int[] mOrigUsers;
- // The set of users that now have this package installed.
- int[] mNewUsers;
- AndroidPackage mPkg;
- int mReturnCode;
- String mReturnMsg;
- String mInstallerPackageName;
- // The set of packages consuming this shared library or null if no consumers exist.
- ArrayList<AndroidPackage> mLibraryConsumers;
- PackageFreezer mFreezer;
- // In some error cases we want to convey more info back to the observer
- String mOrigPackage;
- String mOrigPermission;
- // The ApexInfo returned by ApexManager#installPackage, used by rebootless APEX install
- ApexInfo mApexInfo;
+ // addForInit
+ InstallRequest(ParsedPackage parsedPackage, int parseFlags, int scanFlags,
+ @Nullable UserHandle user, ScanResult scanResult) {
+ if (user != null) {
+ mUserId = user.getIdentifier();
+ } else {
+ // APEX
+ mUserId = INVALID_UID;
+ }
+ mInstallArgs = null;
+ mParsedPackage = parsedPackage;
+ mParseFlags = parseFlags;
+ mScanFlags = scanFlags;
+ mScanResult = scanResult;
}
+ @Nullable
public String getName() {
- return mInstalledInfo.mName;
+ return mName;
}
+ @Nullable
public String getReturnMsg() {
- return mInstalledInfo.mReturnMsg;
+ return mReturnMsg;
}
+ @Nullable
public OriginInfo getOriginInfo() {
return mInstallArgs == null ? null : mInstallArgs.mOriginInfo;
}
+ @Nullable
public PackageRemovedInfo getRemovedInfo() {
return mRemovedInfo;
}
+ @Nullable
public String getOrigPackage() {
- return mInstalledInfo.mOrigPackage;
+ return mOrigPackage;
}
+ @Nullable
public String getOrigPermission() {
- return mInstalledInfo.mOrigPermission;
+ return mOrigPermission;
}
@Nullable
@@ -140,7 +192,7 @@
}
public int getReturnCode() {
- return mInstalledInfo.mReturnCode;
+ return mReturnCode;
}
@Nullable
@@ -160,13 +212,13 @@
@Nullable
public String getMovePackageName() {
- return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
+ return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
? mInstallArgs.mMoveInfo.mPackageName : null;
}
@Nullable
public String getMoveFromCodePath() {
- return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
+ return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
? mInstallArgs.mMoveInfo.mFromCodePath : null;
}
@@ -203,8 +255,9 @@
return mInstallArgs == null ? null : mInstallArgs.mVolumeUuid;
}
+ @Nullable
public AndroidPackage getPkg() {
- return mInstalledInfo.mPkg;
+ return mPkg;
}
@Nullable
@@ -256,13 +309,15 @@
@Nullable
public Uri getOriginUri() {
- return mInstallArgs == null ? null : Uri.fromFile(mInstallArgs.mOriginInfo.mResolvedFile);
+ return mInstallArgs == null ? null : Uri.fromFile(mInstallArgs.mOriginInfo.mResolvedFile);
}
+ @Nullable
public ApexInfo getApexInfo() {
- return mInstalledInfo.mApexInfo;
+ return mApexInfo;
}
+ @Nullable
public String getSourceInstallerPackageName() {
return mInstallArgs.mInstallSource.installerPackageName;
}
@@ -272,25 +327,33 @@
&& mInstallArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
}
+ @Nullable
public int[] getNewUsers() {
- return mInstalledInfo.mNewUsers;
+ return mNewUsers;
}
+ @Nullable
public int[] getOriginUsers() {
- return mInstalledInfo.mOrigUsers;
+ return mOrigUsers;
}
public int getUid() {
- return mInstalledInfo.mUid;
+ return mUid;
}
@Nullable
public String[] getInstallGrantPermissions() {
- return mInstallArgs == null ? null : mInstallArgs.mInstallGrantPermissions;
+ return mInstallArgs == null ? null : mInstallArgs.mInstallGrantPermissions;
}
+ @Nullable
public ArrayList<AndroidPackage> getLibraryConsumers() {
- return mInstalledInfo.mLibraryConsumers;
+ return mLibraryConsumers;
+ }
+
+ @Nullable
+ public AndroidPackage getExistingPackage() {
+ return mExistingPackage;
}
@Nullable
@@ -312,13 +375,170 @@
return mInstallArgs == null ? INSTALL_SCENARIO_DEFAULT : mInstallArgs.mInstallScenario;
}
+ @Nullable
+ public ParsedPackage getParsedPackage() {
+ return mParsedPackage;
+ }
+
+ public @ParsingPackageUtils.ParseFlags int getParseFlags() {
+ return mParseFlags;
+ }
+
+ public @PackageManagerService.ScanFlags int getScanFlags() {
+ return mScanFlags;
+ }
+
+ @Nullable
+ public String getExistingPackageName() {
+ if (mExistingPackage != null) {
+ return mExistingPackage.getPackageName();
+ }
+ return null;
+ }
+
+ @Nullable
+ public AndroidPackage getScanRequestOldPackage() {
+ assertScanResultExists();
+ return mScanResult.mRequest.mOldPkg;
+ }
+
+ public boolean isClearCodeCache() {
+ return mClearCodeCache;
+ }
+
+ public boolean isReplace() {
+ return mReplace;
+ }
+
+ public boolean isSystem() {
+ return mSystem;
+ }
+
+ @Nullable
+ public PackageSetting getOriginalPackageSetting() {
+ return mOriginalPs;
+ }
+
+ @Nullable
+ public PackageSetting getDisabledPackageSetting() {
+ return mDisabledPs;
+ }
+
+ @Nullable
+ public PackageSetting getScanRequestOldPackageSetting() {
+ assertScanResultExists();
+ return mScanResult.mRequest.mOldPkgSetting;
+ }
+
+ @Nullable
+ public PackageSetting getScanRequestOriginalPackageSetting() {
+ assertScanResultExists();
+ return mScanResult.mRequest.mOriginalPkgSetting;
+ }
+
+ @Nullable
+ public PackageSetting getScanRequestPackageSetting() {
+ assertScanResultExists();
+ return mScanResult.mRequest.mPkgSetting;
+ }
+
+ @Nullable
+ public String getRealPackageName() {
+ assertScanResultExists();
+ return mScanResult.mRequest.mRealPkgName;
+ }
+
+ @Nullable
+ public List<String> getChangedAbiCodePath() {
+ assertScanResultExists();
+ return mScanResult.mChangedAbiCodePath;
+ }
+
public boolean isForceQueryableOverride() {
return mInstallArgs != null && mInstallArgs.mForceQueryableOverride;
}
+ @Nullable
+ public SharedLibraryInfo getSdkSharedLibraryInfo() {
+ assertScanResultExists();
+ return mScanResult.mSdkSharedLibraryInfo;
+ }
+
+ @Nullable
+ public SharedLibraryInfo getStaticSharedLibraryInfo() {
+ assertScanResultExists();
+ return mScanResult.mStaticSharedLibraryInfo;
+ }
+
+ @Nullable
+ public List<SharedLibraryInfo> getDynamicSharedLibraryInfos() {
+ assertScanResultExists();
+ return mScanResult.mDynamicSharedLibraryInfos;
+ }
+
+ @Nullable
+ public PackageSetting getScannedPackageSetting() {
+ assertScanResultExists();
+ return mScanResult.mPkgSetting;
+ }
+
+ @Nullable
+ public PackageSetting getRealPackageSetting() {
+ // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
+ // setting needs to be passed to have a comparison, hide it behind an immutable
+ // interface. There's no good reason to have 3 different ways to access the real
+ // PackageSetting object, only one of which is actually correct.
+ PackageSetting realPkgSetting = isExistingSettingCopied()
+ ? getScanRequestPackageSetting() : getScannedPackageSetting();
+ if (realPkgSetting == null) {
+ realPkgSetting = getScannedPackageSetting();
+ }
+ return realPkgSetting;
+ }
+
+ public boolean isExistingSettingCopied() {
+ assertScanResultExists();
+ return mScanResult.mExistingSettingCopied;
+ }
+
+ /**
+ * Whether the original PackageSetting needs to be updated with
+ * a new app ID. Useful when leaving a sharedUserId.
+ */
+ public boolean needsNewAppId() {
+ assertScanResultExists();
+ return mScanResult.mPreviousAppId != Process.INVALID_UID;
+ }
+
+ public int getPreviousAppId() {
+ assertScanResultExists();
+ return mScanResult.mPreviousAppId;
+ }
+
+ public boolean isPlatformPackage() {
+ assertScanResultExists();
+ return mScanResult.mRequest.mIsPlatformPackage;
+ }
+
+ public void assertScanResultExists() {
+ if (mScanResult == null) {
+ // Should not happen. This indicates a bug in the installation code flow
+ if (Build.IS_USERDEBUG || Build.IS_ENG) {
+ throw new IllegalStateException("ScanResult cannot be null.");
+ } else {
+ Slog.e(TAG, "ScanResult is null and it should not happen");
+ }
+ }
+
+ }
+
+ public void setScanFlags(int scanFlags) {
+ mScanFlags = scanFlags;
+ }
+
public void closeFreezer() {
- if (mInstalledInfo.mFreezer != null) {
- mInstalledInfo.mFreezer.close();
+ if (mFreezer != null) {
+ mFreezer.close();
}
}
@@ -341,57 +561,53 @@
}
public void setError(String msg, PackageManagerException e) {
- mInstalledInfo.mReturnCode = e.error;
+ mReturnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
public void setReturnCode(int returnCode) {
- mInstalledInfo.mReturnCode = returnCode;
+ mReturnCode = returnCode;
}
public void setReturnMessage(String returnMsg) {
- mInstalledInfo.mReturnMsg = returnMsg;
+ mReturnMsg = returnMsg;
}
public void setApexInfo(ApexInfo apexInfo) {
- mInstalledInfo.mApexInfo = apexInfo;
+ mApexInfo = apexInfo;
}
public void setPkg(AndroidPackage pkg) {
- mInstalledInfo.mPkg = pkg;
+ mPkg = pkg;
}
public void setUid(int uid) {
- mInstalledInfo.mUid = uid;
+ mUid = uid;
}
public void setNewUsers(int[] newUsers) {
- mInstalledInfo.mNewUsers = newUsers;
+ mNewUsers = newUsers;
}
public void setOriginPackage(String originPackage) {
- mInstalledInfo.mOrigPackage = originPackage;
+ mOrigPackage = originPackage;
}
public void setOriginPermission(String originPermission) {
- mInstalledInfo.mOrigPermission = originPermission;
- }
-
- public void setInstallerPackageName(String installerPackageName) {
- mInstalledInfo.mInstallerPackageName = installerPackageName;
+ mOrigPermission = originPermission;
}
public void setName(String packageName) {
- mInstalledInfo.mName = packageName;
+ mName = packageName;
}
public void setOriginUsers(int[] userIds) {
- mInstalledInfo.mOrigUsers = userIds;
+ mOrigUsers = userIds;
}
public void setFreezer(PackageFreezer freezer) {
- mInstalledInfo.mFreezer = freezer;
+ mFreezer = freezer;
}
public void setRemovedInfo(PackageRemovedInfo removedInfo) {
@@ -399,6 +615,47 @@
}
public void setLibraryConsumers(ArrayList<AndroidPackage> libraryConsumers) {
- mInstalledInfo.mLibraryConsumers = libraryConsumers;
+ mLibraryConsumers = libraryConsumers;
+ }
+
+ public void setPrepareResult(boolean replace, int scanFlags,
+ int parseFlags, AndroidPackage existingPackage,
+ ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
+ PackageSetting originalPs, PackageSetting disabledPs) {
+ mReplace = replace;
+ mScanFlags = scanFlags;
+ mParseFlags = parseFlags;
+ mExistingPackage = existingPackage;
+ mParsedPackage = packageToScan;
+ mClearCodeCache = clearCodeCache;
+ mSystem = system;
+ mOriginalPs = originalPs;
+ mDisabledPs = disabledPs;
+ }
+
+ public void setScanResult(@NonNull ScanResult scanResult) {
+ mScanResult = scanResult;
+ }
+
+ public void setScannedPackageSettingAppId(int appId) {
+ assertScanResultExists();
+ mScanResult.mPkgSetting.setAppId(appId);
+ }
+
+ public void setScannedPackageSettingFirstInstallTimeFromReplaced(
+ @Nullable PackageStateInternal replacedPkgSetting, int[] userId) {
+ assertScanResultExists();
+ mScanResult.mPkgSetting.setFirstInstallTimeFromReplaced(replacedPkgSetting, userId);
+ }
+
+ public void setScannedPackageSettingLastUpdateTime(long lastUpdateTim) {
+ assertScanResultExists();
+ mScanResult.mPkgSetting.setLastUpdateTime(lastUpdateTim);
+ }
+
+ public void setRemovedAppId(int appId) {
+ if (mRemovedInfo != null) {
+ mRemovedInfo.mRemovedAppId = appId;
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 8d5a5e1..16b3a81 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -42,7 +42,7 @@
import android.os.Environment;
import android.os.Trace;
import android.os.UserHandle;
-import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
@@ -60,7 +60,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
+import java.util.Set;
class InstallingSession {
final OriginInfo mOriginInfo;
@@ -599,7 +599,7 @@
*/
private class MultiPackageInstallingSession {
private final List<InstallingSession> mChildInstallingSessions;
- private final Map<InstallRequest, Integer> mCurrentState;
+ private final Set<InstallRequest> mCurrentInstallRequests;
@NonNull
final PackageManagerService mPm;
final UserHandle mUser;
@@ -618,7 +618,7 @@
final InstallingSession childInstallingSession = childInstallingSessions.get(i);
childInstallingSession.mParentInstallingSession = this;
}
- this.mCurrentState = new ArrayMap<>(mChildInstallingSessions.size());
+ mCurrentInstallRequests = new ArraySet<>(mChildInstallingSessions.size());
}
public void start() {
@@ -636,23 +636,24 @@
}
public void tryProcessInstallRequest(InstallRequest request) {
- mCurrentState.put(request, request.getReturnCode());
- if (mCurrentState.size() != mChildInstallingSessions.size()) {
+ mCurrentInstallRequests.add(request);
+ if (mCurrentInstallRequests.size() != mChildInstallingSessions.size()) {
return;
}
int completeStatus = PackageManager.INSTALL_SUCCEEDED;
- for (Integer status : mCurrentState.values()) {
- if (status == PackageManager.INSTALL_UNKNOWN) {
+ for (InstallRequest installRequest : mCurrentInstallRequests) {
+ if (installRequest.getReturnCode() == PackageManager.INSTALL_UNKNOWN) {
return;
- } else if (status != PackageManager.INSTALL_SUCCEEDED) {
- completeStatus = status;
+ } else if (installRequest.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
+ completeStatus = installRequest.getReturnCode();
break;
}
}
- final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
- for (Map.Entry<InstallRequest, Integer> entry : mCurrentState.entrySet()) {
- entry.getKey().setReturnCode(completeStatus);
- installRequests.add(entry.getKey());
+ final List<InstallRequest> installRequests = new ArrayList<>(
+ mCurrentInstallRequests.size());
+ for (InstallRequest installRequest : mCurrentInstallRequests) {
+ installRequest.setReturnCode(completeStatus);
+ installRequests.add(installRequest);
}
int finalCompleteStatus = completeStatus;
mPm.mHandler.post(() -> processInstallRequests(
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index bedc12a..032d030 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -46,8 +46,6 @@
import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -55,6 +53,8 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 7774b6a..f1453c8 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -27,9 +27,9 @@
import android.util.Base64;
import android.util.LongSparseArray;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 218d9d1..cc1d879 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -78,8 +78,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.R;
@@ -89,6 +87,8 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 022bf3c..5df73a6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,6 +29,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
+import static android.content.pm.PackageManager.INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
@@ -139,8 +140,6 @@
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.apk.ApkSignatureVerifier;
import com.android.internal.R;
@@ -156,6 +155,8 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
@@ -4243,6 +4244,13 @@
public void requestUserPreapproval(@NonNull PreapprovalDetails details,
@NonNull IntentSender statusReceiver) {
validatePreapprovalRequest(details, statusReceiver);
+
+ if (!mPm.isPreapprovalRequestAvailable()) {
+ sendUpdateToRemoteStatusReceiver(INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE,
+ "Request user pre-approval is currently not available.", null /* extras */);
+ return;
+ }
+
dispatchPreapprovalRequest();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6e54d0b..dfbe68a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -161,8 +161,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -181,6 +179,8 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
@@ -495,6 +495,15 @@
private static final String PROPERTY_KNOWN_DIGESTERS_LIST = "known_digesters_list";
/**
+ * Whether of not requesting the approval before committing sessions is available.
+ *
+ * Flag type: {@code boolean}
+ * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
+ */
+ private static final String PROPERTY_IS_PRE_APPROVAL_REQUEST_AVAILABLE =
+ "is_preapproval_available";
+
+ /**
* The default response for package verification timeout.
*
* This can be either PackageManager.VERIFICATION_ALLOW or
@@ -6894,6 +6903,16 @@
}
}
+ static boolean isPreapprovalRequestAvailable() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(NAMESPACE_PACKAGE_MANAGER_SERVICE,
+ PROPERTY_IS_PRE_APPROVAL_REQUEST_AVAILABLE, true /* defaultValue */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Returns the array containing per-uid timeout configuration.
* This is derived from DeviceConfig flags.
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 76858d9..3c1cba3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -316,6 +316,8 @@
return runCreateUser();
case "remove-user":
return runRemoveUser();
+ case "rename-user":
+ return runRenameUser();
case "set-user-restriction":
return runSetUserRestriction();
case "supports-multiple-users":
@@ -3024,6 +3026,28 @@
}
}
+ private int runRenameUser() throws RemoteException {
+ String arg = getNextArg();
+ if (arg == null) {
+ getErrPrintWriter().println("Error: no user id specified.");
+ return 1;
+ }
+ int userId = resolveUserId(UserHandle.parseUserArg(arg));
+
+ String name = getNextArg();
+ if (name == null) {
+ Slog.i(TAG, "Resetting name of user " + userId);
+ } else {
+ Slog.i(TAG, "Renaming user " + userId + " to '" + name + "'");
+ }
+
+ IUserManager um = IUserManager.Stub.asInterface(
+ ServiceManager.getService(Context.USER_SERVICE));
+ um.setUserName(userId, name);
+
+ return 0;
+ }
+
public int runSetUserRestriction() throws RemoteException {
int userId = UserHandle.USER_SYSTEM;
String opt = getNextOption();
@@ -3937,6 +3961,11 @@
return res;
}
+ // Resolves the userId; supports UserHandle.USER_CURRENT, but not other special values
+ private @UserIdInt int resolveUserId(@UserIdInt int userId) {
+ return userId == UserHandle.USER_CURRENT ? ActivityManager.getCurrentUser() : userId;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -4208,6 +4237,9 @@
pw.println(" switch or reboot)");
pw.println(" --wait: Wait until user is removed. Ignored if set-ephemeral-if-in-use");
pw.println("");
+ pw.println(" rename-user USER_ID [USER_NAME]");
+ pw.println(" Rename USER_ID with USER_NAME (or null when [USER_NAME] is not set)");
+ pw.println("");
pw.println(" set-user-restriction [--user USER_ID] RESTRICTION VALUE");
pw.println("");
pw.println(" get-max-users");
diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
index 76364fe..90f57a7 100644
--- a/services/core/java/com/android/server/pm/PackageSignatures.java
+++ b/services/core/java/com/android/server/pm/PackageSignatures.java
@@ -21,10 +21,10 @@
import android.content.pm.SigningDetails;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
index ad3950c..d0ee0c8 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -19,10 +19,10 @@
import android.content.ComponentName;
import android.content.IntentFilter;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.utils.SnapshotCache;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/PreferredActivity.java b/services/core/java/com/android/server/pm/PreferredActivity.java
index 5bc915f..1a49bf9 100644
--- a/services/core/java/com/android/server/pm/PreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PreferredActivity.java
@@ -19,10 +19,10 @@
import android.content.ComponentName;
import android.content.IntentFilter;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.utils.SnapshotCache;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 0ca5febd..e7727f0 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -42,11 +42,11 @@
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseBooleanArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.ArrayUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.pkg.PackageStateInternal;
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 2a1ca2c..5507e7c 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -23,10 +23,10 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.pm.pkg.PackageUserState;
diff --git a/services/core/java/com/android/server/pm/PrepareResult.java b/services/core/java/com/android/server/pm/PrepareResult.java
deleted file mode 100644
index e074f44a..0000000
--- a/services/core/java/com/android/server/pm/PrepareResult.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.annotation.Nullable;
-
-import com.android.server.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.AndroidPackage;
-
-/**
- * The set of data needed to successfully install the prepared package. This includes data that
- * will be used to scan and reconcile the package.
- */
-final class PrepareResult {
- public final boolean mReplace;
- public final int mScanFlags;
- public final int mParseFlags;
- @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
- public final AndroidPackage mExistingPackage;
- public final ParsedPackage mPackageToScan;
- public final boolean mClearCodeCache;
- public final boolean mSystem;
- public final PackageSetting mOriginalPs;
- public final PackageSetting mDisabledPs;
-
- PrepareResult(boolean replace, int scanFlags,
- int parseFlags, AndroidPackage existingPackage,
- ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
- PackageSetting originalPs, PackageSetting disabledPs) {
- mReplace = replace;
- mScanFlags = scanFlags;
- mParseFlags = parseFlags;
- mExistingPackage = existingPackage;
- mPackageToScan = packageToScan;
- mClearCodeCache = clearCodeCache;
- mSystem = system;
- mOriginalPs = originalPs;
- mDisabledPs = disabledPs;
- }
-}
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 165b450..ffce69e 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -38,34 +38,44 @@
import java.util.List;
import java.util.Map;
+/**
+ * Package scan results and related request details used to reconcile the potential addition of
+ * one or more packages to the system.
+ *
+ * Reconcile will take a set of package details that need to be committed to the system and make
+ * sure that they are valid in the context of the system and the other installing apps. Any
+ * invalid state or app will result in a failed reconciliation and thus whatever operation (such
+ * as install) led to the request.
+ */
final class ReconcilePackageUtils {
public static Map<String, ReconciledPackage> reconcilePackages(
- final ReconcileRequest request, SharedLibrariesImpl sharedLibraries,
+ List<InstallRequest> installRequests,
+ Map<String, AndroidPackage> allPackages,
+ Map<String, Settings.VersionInfo> versionInfos,
+ SharedLibrariesImpl sharedLibraries,
KeySetManagerService ksms, Settings settings)
throws ReconcileFailure {
- final Map<String, ScanResult> scannedPackages = request.mScannedPackages;
-
- final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
+ final Map<String, ReconciledPackage> result = new ArrayMap<>(installRequests.size());
// make a copy of the existing set of packages so we can combine them with incoming packages
final ArrayMap<String, AndroidPackage> combinedPackages =
- new ArrayMap<>(request.mAllPackages.size() + scannedPackages.size());
+ new ArrayMap<>(allPackages.size() + installRequests.size());
- combinedPackages.putAll(request.mAllPackages);
+ combinedPackages.putAll(allPackages);
final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
new ArrayMap<>();
- for (String installPackageName : scannedPackages.keySet()) {
- final ScanResult scanResult = scannedPackages.get(installPackageName);
+ for (InstallRequest installRequest : installRequests) {
+ final String installPackageName = installRequest.getParsedPackage().getPackageName();
// add / replace existing with incoming packages
- combinedPackages.put(scanResult.mPkgSetting.getPackageName(),
- scanResult.mRequest.mParsedPackage);
+ combinedPackages.put(installRequest.getScannedPackageSetting().getPackageName(),
+ installRequest.getParsedPackage());
// in the first pass, we'll build up the set of incoming shared libraries
final List<SharedLibraryInfo> allowedSharedLibInfos =
- sharedLibraries.getAllowedSharedLibInfos(scanResult);
+ sharedLibraries.getAllowedSharedLibInfos(installRequest);
if (allowedSharedLibInfos != null) {
for (SharedLibraryInfo info : allowedSharedLibInfos) {
if (!SharedLibraryUtils.addSharedLibraryToPackageVersionMap(
@@ -76,24 +86,18 @@
}
}
- // the following may be null if we're just reconciling on boot (and not during install)
- final InstallRequest installRequest = request.mInstallRequests.get(installPackageName);
- final PrepareResult prepareResult = request.mPreparedPackages.get(installPackageName);
- final boolean isInstall = installRequest != null;
- if (isInstall && prepareResult == null) {
- throw new ReconcileFailure("Reconcile arguments are not balanced for "
- + installPackageName + "!");
- }
+
final DeletePackageAction deletePackageAction;
// we only want to try to delete for non system apps
- if (isInstall && prepareResult.mReplace && !prepareResult.mSystem) {
- final boolean killApp = (scanResult.mRequest.mScanFlags & SCAN_DONT_KILL_APP) == 0;
+ if (installRequest.isReplace() && !installRequest.isSystem()) {
+ final boolean killApp = (installRequest.getScanFlags() & SCAN_DONT_KILL_APP) == 0;
final int deleteFlags = PackageManager.DELETE_KEEP_DATA
| (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
deletePackageAction = DeletePackageHelper.mayDeletePackageLocked(
installRequest.getRemovedInfo(),
- prepareResult.mOriginalPs, prepareResult.mDisabledPs,
+ installRequest.getOriginalPackageSetting(),
+ installRequest.getDisabledPackageSetting(),
deleteFlags, null /* all users */);
if (deletePackageAction == null) {
throw new ReconcileFailure(
@@ -104,21 +108,24 @@
deletePackageAction = null;
}
- final int scanFlags = scanResult.mRequest.mScanFlags;
- final int parseFlags = scanResult.mRequest.mParseFlags;
- final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage;
-
- final PackageSetting disabledPkgSetting = scanResult.mRequest.mDisabledPkgSetting;
+ final int scanFlags = installRequest.getScanFlags();
+ final int parseFlags = installRequest.getParseFlags();
+ final ParsedPackage parsedPackage = installRequest.getParsedPackage();
+ final PackageSetting disabledPkgSetting = installRequest.getDisabledPackageSetting();
final PackageSetting lastStaticSharedLibSetting =
- scanResult.mStaticSharedLibraryInfo == null ? null
- : sharedLibraries.getStaticSharedLibLatestVersionSetting(scanResult);
+ installRequest.getStaticSharedLibraryInfo() == null ? null
+ : sharedLibraries.getStaticSharedLibLatestVersionSetting(
+ installRequest);
final PackageSetting signatureCheckPs =
- (prepareResult != null && lastStaticSharedLibSetting != null)
+ lastStaticSharedLibSetting != null
? lastStaticSharedLibSetting
- : scanResult.mPkgSetting;
+ : installRequest.getScannedPackageSetting();
boolean removeAppKeySetData = false;
boolean sharedUserSignaturesChanged = false;
SigningDetails signingDetails = null;
+ if (parsedPackage != null) {
+ signingDetails = parsedPackage.getSigningDetails();
+ }
SharedUserSetting sharedUserSetting = settings.getSharedUserSettingLPr(
signatureCheckPs);
if (ksms.shouldCheckUpgradeKeySetLocked(
@@ -138,28 +145,21 @@
PackageManagerService.reportSettingsProblem(Log.WARN, msg);
}
}
- signingDetails = parsedPackage.getSigningDetails();
} else {
-
try {
- final Settings.VersionInfo versionInfo =
- request.mVersionInfos.get(installPackageName);
+ final Settings.VersionInfo versionInfo = versionInfos.get(installPackageName);
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
- final boolean isRollback = installRequest != null
- && installRequest.isRollback();
+ final boolean isRollback = installRequest.isRollback();
final boolean compatMatch =
PackageManagerServiceUtils.verifySignatures(signatureCheckPs,
sharedUserSetting, disabledPkgSetting,
- parsedPackage.getSigningDetails(), compareCompat,
+ signingDetails, compareCompat,
compareRecover, isRollback);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
removeAppKeySetData = true;
}
- // We just determined the app is signed correctly, so bring
- // over the latest parsed certs.
- signingDetails = parsedPackage.getSigningDetails();
// if this is is a sharedUser, check to see if the new package is signed by a
// newer
@@ -257,13 +257,12 @@
}
result.put(installPackageName,
- new ReconciledPackage(request, installRequest, scanResult.mPkgSetting,
- request.mPreparedPackages.get(installPackageName), scanResult,
+ new ReconciledPackage(installRequests, allPackages, installRequest,
deletePackageAction, allowedSharedLibInfos, signingDetails,
sharedUserSignaturesChanged, removeAppKeySetData));
}
- for (String installPackageName : scannedPackages.keySet()) {
+ for (InstallRequest installRequest : installRequests) {
// Check all shared libraries and map to their actual file path.
// We only do this here for apps not on a system dir, because those
// are the only ones that can fail an install due to this. We
@@ -271,16 +270,16 @@
// library paths after the scan is done. Also during the initial
// scan don't update any libs as we do this wholesale after all
// apps are scanned to avoid dependency based scanning.
- final ScanResult scanResult = scannedPackages.get(installPackageName);
- if ((scanResult.mRequest.mScanFlags & SCAN_BOOTING) != 0
- || (scanResult.mRequest.mParseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
+ if ((installRequest.getScanFlags() & SCAN_BOOTING) != 0
+ || (installRequest.getParseFlags() & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
!= 0) {
continue;
}
+ final String installPackageName = installRequest.getParsedPackage().getPackageName();
try {
result.get(installPackageName).mCollectedSharedLibraryInfos =
sharedLibraries.collectSharedLibraryInfos(
- scanResult.mRequest.mParsedPackage, combinedPackages,
+ installRequest.getParsedPackage(), combinedPackages,
incomingSharedLibraries);
} catch (PackageManagerException e) {
throw new ReconcileFailure(e.error, e.getMessage());
diff --git a/services/core/java/com/android/server/pm/ReconcileRequest.java b/services/core/java/com/android/server/pm/ReconcileRequest.java
deleted file mode 100644
index 3568c15..0000000
--- a/services/core/java/com/android/server/pm/ReconcileRequest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import com.android.server.pm.pkg.AndroidPackage;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Package scan results and related request details used to reconcile the potential addition of
- * one or more packages to the system.
- *
- * Reconcile will take a set of package details that need to be committed to the system and make
- * sure that they are valid in the context of the system and the other installing apps. Any
- * invalid state or app will result in a failed reconciliation and thus whatever operation (such
- * as install) led to the request.
- */
-final class ReconcileRequest {
- public final Map<String, ScanResult> mScannedPackages;
-
- public final Map<String, AndroidPackage> mAllPackages;
- public final Map<String, InstallRequest> mInstallRequests;
- public final Map<String, PrepareResult> mPreparedPackages;
- public final Map<String, Settings.VersionInfo> mVersionInfos;
-
- ReconcileRequest(Map<String, ScanResult> scannedPackages,
- Map<String, InstallRequest> installRequests,
- Map<String, PrepareResult> preparedPackages,
- Map<String, AndroidPackage> allPackages,
- Map<String, Settings.VersionInfo> versionInfos) {
- mScannedPackages = scannedPackages;
- mInstallRequests = installRequests;
- mPreparedPackages = preparedPackages;
- mAllPackages = allPackages;
- mVersionInfos = versionInfos;
- }
-
- ReconcileRequest(Map<String, ScanResult> scannedPackages,
- Map<String, AndroidPackage> allPackages,
- Map<String, Settings.VersionInfo> versionInfos) {
- this(scannedPackages, Collections.emptyMap(),
- Collections.emptyMap(), allPackages, versionInfos);
- }
-}
diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java
index d4da6c7..701baee 100644
--- a/services/core/java/com/android/server/pm/ReconciledPackage.java
+++ b/services/core/java/com/android/server/pm/ReconciledPackage.java
@@ -17,7 +17,6 @@
package com.android.server.pm;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.util.ArrayMap;
@@ -33,12 +32,9 @@
* TODO: move most of the data contained here into a PackageSetting for commit.
*/
final class ReconciledPackage {
- public final ReconcileRequest mRequest;
- public final PackageSetting mPkgSetting;
- public final ScanResult mScanResult;
- // TODO: Remove install-specific details from the reconcile result
- @Nullable public final PrepareResult mPrepareResult;
- @Nullable public final InstallRequest mInstallRequest;
+ private final List<InstallRequest> mInstallRequests;
+ private final Map<String, AndroidPackage> mAllPackages;
+ @NonNull public final InstallRequest mInstallRequest;
public final DeletePackageAction mDeletePackageAction;
public final List<SharedLibraryInfo> mAllowedSharedLibraryInfos;
public final SigningDetails mSigningDetails;
@@ -46,21 +42,17 @@
public ArrayList<SharedLibraryInfo> mCollectedSharedLibraryInfos;
public final boolean mRemoveAppKeySetData;
- ReconciledPackage(ReconcileRequest request,
+ ReconciledPackage(List<InstallRequest> installRequests,
+ Map<String, AndroidPackage> allPackages,
InstallRequest installRequest,
- PackageSetting pkgSetting,
- PrepareResult prepareResult,
- ScanResult scanResult,
DeletePackageAction deletePackageAction,
List<SharedLibraryInfo> allowedSharedLibraryInfos,
SigningDetails signingDetails,
boolean sharedUserSignaturesChanged,
boolean removeAppKeySetData) {
- mRequest = request;
+ mInstallRequests = installRequests;
+ mAllPackages = allPackages;
mInstallRequest = installRequest;
- mPkgSetting = pkgSetting;
- mPrepareResult = prepareResult;
- mScanResult = scanResult;
mDeletePackageAction = deletePackageAction;
mAllowedSharedLibraryInfos = allowedSharedLibraryInfos;
mSigningDetails = signingDetails;
@@ -75,13 +67,13 @@
*/
@NonNull Map<String, AndroidPackage> getCombinedAvailablePackages() {
final ArrayMap<String, AndroidPackage> combined =
- new ArrayMap<>(mRequest.mAllPackages.size() + mRequest.mScannedPackages.size());
+ new ArrayMap<>(mAllPackages.size() + mInstallRequests.size());
- combined.putAll(mRequest.mAllPackages);
+ combined.putAll(mAllPackages);
- for (ScanResult scanResult : mRequest.mScannedPackages.values()) {
- combined.put(scanResult.mPkgSetting.getPackageName(),
- scanResult.mRequest.mParsedPackage);
+ for (InstallRequest installRequest : mInstallRequests) {
+ combined.put(installRequest.getScannedPackageSetting().getPackageName(),
+ installRequest.getParsedPackage());
}
return combined;
diff --git a/services/core/java/com/android/server/pm/RestrictionsSet.java b/services/core/java/com/android/server/pm/RestrictionsSet.java
index e5a70c3..e7ad5b9 100644
--- a/services/core/java/com/android/server/pm/RestrictionsSet.java
+++ b/services/core/java/com/android/server/pm/RestrictionsSet.java
@@ -22,10 +22,10 @@
import android.os.Bundle;
import android.os.UserManager;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.BundleUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index bd3c7dd..a905df9 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -462,7 +462,7 @@
}
}
- return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
+ return new ScanResult(request, pkgSetting, changedAbiCodePath,
!createNewPackage /* existingSettingCopied */,
Process.INVALID_UID /* previousAppId */ , sdkLibraryInfo,
staticSharedLibraryInfo, dynamicSharedLibraryInfos);
diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java
index e2860ca..750e893 100644
--- a/services/core/java/com/android/server/pm/ScanResult.java
+++ b/services/core/java/com/android/server/pm/ScanResult.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.SharedLibraryInfo;
import android.os.Process;
@@ -28,9 +29,7 @@
@VisibleForTesting
final class ScanResult {
/** The request that initiated the scan that produced this result. */
- public final ScanRequest mRequest;
- /** Whether or not the package scan was successful */
- public final boolean mSuccess;
+ @NonNull public final ScanRequest mRequest;
/**
* Whether or not the original PackageSetting needs to be updated with this result on
* commit.
@@ -58,7 +57,7 @@
public final List<SharedLibraryInfo> mDynamicSharedLibraryInfos;
ScanResult(
- ScanRequest request, boolean success,
+ @NonNull ScanRequest request,
@Nullable PackageSetting pkgSetting,
@Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
int previousAppId,
@@ -66,7 +65,6 @@
SharedLibraryInfo staticSharedLibraryInfo,
List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
mRequest = request;
- mSuccess = success;
mPkgSetting = pkgSetting;
mChangedAbiCodePath = changedAbiCodePath;
mExistingSettingCopied = existingSettingCopied;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f2a7651..0eefbfe 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -83,8 +83,6 @@
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -96,6 +94,8 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.permission.persistence.RuntimePermissionsState;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/pm/SettingsXml.java b/services/core/java/com/android/server/pm/SettingsXml.java
index c53fef7..5fb6731 100644
--- a/services/core/java/com/android/server/pm/SettingsXml.java
+++ b/services/core/java/com/android/server/pm/SettingsXml.java
@@ -19,10 +19,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/ShareTargetInfo.java b/services/core/java/com/android/server/pm/ShareTargetInfo.java
index 660874e..bfb5f39 100644
--- a/services/core/java/com/android/server/pm/ShareTargetInfo.java
+++ b/services/core/java/com/android/server/pm/ShareTargetInfo.java
@@ -17,8 +17,9 @@
import android.annotation.NonNull;
import android.text.TextUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 094e748..aa23d8d 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -422,15 +422,18 @@
* Given a package scanned result of a static shared library, returns its package setting of
* the latest version
*
- * @param scanResult The scanned result of a static shared library package.
+ * @param installRequest The install result of a static shared library package.
* @return The package setting that represents the latest version of shared library info.
*/
@Nullable
- PackageSetting getStaticSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+ PackageSetting getStaticSharedLibLatestVersionSetting(@NonNull InstallRequest installRequest) {
+ if (installRequest.getParsedPackage() == null) {
+ return null;
+ }
PackageSetting sharedLibPackage = null;
synchronized (mPm.mLock) {
final SharedLibraryInfo latestSharedLibraVersionLPr =
- getLatestStaticSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
+ getLatestStaticSharedLibraVersionLPr(installRequest.getParsedPackage());
if (latestSharedLibraVersionLPr != null) {
sharedLibPackage = mPm.mSettings.getPackageLPr(
latestSharedLibraVersionLPr.getPackageName());
@@ -823,34 +826,35 @@
* Compare the newly scanned package with current system state to see which of its declared
* shared libraries should be allowed to be added to the system.
*/
- List<SharedLibraryInfo> getAllowedSharedLibInfos(ScanResult scanResult) {
+ List<SharedLibraryInfo> getAllowedSharedLibInfos(InstallRequest installRequest) {
// Let's used the parsed package as scanResult.pkgSetting may be null
- final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage;
- if (scanResult.mSdkSharedLibraryInfo == null && scanResult.mStaticSharedLibraryInfo == null
- && scanResult.mDynamicSharedLibraryInfos == null) {
+ final ParsedPackage parsedPackage = installRequest.getParsedPackage();
+ if (installRequest.getSdkSharedLibraryInfo() == null
+ && installRequest.getStaticSharedLibraryInfo() == null
+ && installRequest.getDynamicSharedLibraryInfos() == null) {
return null;
}
// Any app can add new SDKs and static shared libraries.
- if (scanResult.mSdkSharedLibraryInfo != null) {
- return Collections.singletonList(scanResult.mSdkSharedLibraryInfo);
+ if (installRequest.getSdkSharedLibraryInfo() != null) {
+ return Collections.singletonList(installRequest.getSdkSharedLibraryInfo());
}
- if (scanResult.mStaticSharedLibraryInfo != null) {
- return Collections.singletonList(scanResult.mStaticSharedLibraryInfo);
+ if (installRequest.getStaticSharedLibraryInfo() != null) {
+ return Collections.singletonList(installRequest.getStaticSharedLibraryInfo());
}
- final boolean hasDynamicLibraries = parsedPackage.isSystem()
- && scanResult.mDynamicSharedLibraryInfos != null;
+ final boolean hasDynamicLibraries = parsedPackage != null && parsedPackage.isSystem()
+ && installRequest.getDynamicSharedLibraryInfos() != null;
if (!hasDynamicLibraries) {
return null;
}
- final boolean isUpdatedSystemApp = scanResult.mPkgSetting.getPkgState()
- .isUpdatedSystemApp();
+ final boolean isUpdatedSystemApp = installRequest.getScannedPackageSetting() != null
+ && installRequest.getScannedPackageSetting().getPkgState().isUpdatedSystemApp();
// We may not yet have disabled the updated package yet, so be sure to grab the
// current setting if that's the case.
final PackageSetting updatedSystemPs = isUpdatedSystemApp
- ? scanResult.mRequest.mDisabledPkgSetting == null
- ? scanResult.mRequest.mOldPkgSetting
- : scanResult.mRequest.mDisabledPkgSetting
+ ? installRequest.getDisabledPackageSetting() == null
+ ? installRequest.getScanRequestOldPackageSetting()
+ : installRequest.getDisabledPackageSetting()
: null;
if (isUpdatedSystemApp && (updatedSystemPs.getPkg() == null
|| updatedSystemPs.getPkg().getLibraryNames() == null)) {
@@ -859,8 +863,8 @@
return null;
}
final ArrayList<SharedLibraryInfo> infos =
- new ArrayList<>(scanResult.mDynamicSharedLibraryInfos.size());
- for (SharedLibraryInfo info : scanResult.mDynamicSharedLibraryInfos) {
+ new ArrayList<>(installRequest.getDynamicSharedLibraryInfos().size());
+ for (SharedLibraryInfo info : installRequest.getDynamicSharedLibraryInfos()) {
final String name = info.getName();
if (isUpdatedSystemApp) {
// New library entries can only be added through the
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index c6a7dd7..0d99075 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -24,11 +24,11 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutUser.PackageWithUser;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 890c891..0362ddd 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -53,8 +53,6 @@
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -65,6 +63,8 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.ShortcutOperation;
import com.android.server.pm.ShortcutService.Stats;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index fce6610..79b725d 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -23,10 +23,10 @@
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.backup.BackupUtils;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 7800183..e20330d 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -22,11 +22,11 @@
import android.graphics.Bitmap;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlSerializer;
import org.json.JSONException;
import org.json.JSONObject;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 0b20683..b6f09ff 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -100,8 +100,6 @@
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TypedValue;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.IWindowManager;
@@ -116,6 +114,8 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.StatLogger;
+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.pm.ShortcutUser.PackageWithUser;
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index b9fd2fd..20bbf46 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -30,14 +30,14 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.FgThread;
import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.InvalidFileFormatException;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 477e260..aeb11b7 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -158,7 +158,7 @@
final AndroidPackage pkg;
try {
pkg = installPackageHelper.scanSystemPackageTracedLI(
- ps.getPath(), parseFlags, SCAN_INITIAL, null);
+ ps.getPath(), parseFlags, SCAN_INITIAL);
loaded.add(pkg);
} catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f578fb5..4966f94 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -103,8 +103,6 @@
import android.util.StatsEvent;
import android.util.TimeUtils;
import android.util.TypedValue;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -119,6 +117,8 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.BundleUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
@@ -2278,26 +2278,31 @@
@Override
public void setUserName(@UserIdInt int userId, String name) {
checkManageUsersPermission("rename users");
- boolean changed = false;
synchronized (mPackagesLock) {
UserData userData = getUserDataNoChecks(userId);
if (userData == null || userData.info.partial) {
- Slog.w(LOG_TAG, "setUserName: unknown user #" + userId);
+ Slogf.w(LOG_TAG, "setUserName: unknown user #%d", userId);
return;
}
- if (name != null && !name.equals(userData.info.name)) {
- userData.info.name = name;
- writeUserLP(userData);
- changed = true;
+ if (Objects.equals(name, userData.info.name)) {
+ Slogf.i(LOG_TAG, "setUserName: ignoring for user #%d as it didn't change (%s)",
+ userId, getRedacted(name));
+ return;
}
+ if (name == null) {
+ Slogf.i(LOG_TAG, "setUserName: resetting name of user #%d", userId);
+ } else {
+ Slogf.i(LOG_TAG, "setUserName: setting name of user #%d to %s", userId,
+ getRedacted(name));
+ }
+ userData.info.name = name;
+ writeUserLP(userData);
}
- if (changed) {
- final long ident = Binder.clearCallingIdentity();
- try {
- sendUserInfoChangedBroadcast(userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ sendUserInfoChangedBroadcast(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -6108,6 +6113,11 @@
return RESTRICTIONS_FILE_PREFIX + packageName + XML_SUFFIX;
}
+ @Nullable
+ private static String getRedacted(@Nullable String string) {
+ return string == null ? null : string.length() + "_chars";
+ }
+
@Override
public void setSeedAccountData(@UserIdInt int userId, String accountName, String accountType,
PersistableBundle accountOptions, boolean persist) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 016c1cb..d1f3341e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -40,11 +40,11 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.BundleUtils;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 37abeac..8588267 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -62,12 +62,12 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.pm.KnownPackages;
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermission.java b/services/core/java/com/android/server/pm/permission/LegacyPermission.java
index 5f8f342..d8b4faa 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermission.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermission.java
@@ -21,9 +21,9 @@
import android.annotation.Nullable;
import android.content.pm.PermissionInfo;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java
index f63600a..fc6d202 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionSettings.java
@@ -21,11 +21,11 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
diff --git a/services/core/java/com/android/server/pm/pkg/SuspendParams.java b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
index 0926ba2..dc48a33 100644
--- a/services/core/java/com/android/server/pm/pkg/SuspendParams.java
+++ b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
@@ -21,8 +21,9 @@
import android.os.BaseBundle;
import android.os.PersistableBundle;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
index 4bad102..9fb8297 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
@@ -23,10 +23,10 @@
import android.content.pm.PackageManager;
import android.util.ArrayMap;
import android.util.SparseIntArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.SettingsXml;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 1714086..53ee189 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -33,9 +33,9 @@
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.Pair;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.Computer;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.Settings;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
index e803457..ac6d795 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
@@ -27,9 +27,9 @@
import android.util.ArraySet;
import android.util.PackageUtils;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.SettingsXml;
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 400af36..595c34c 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -46,11 +46,11 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.CollectionUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.compat.PlatformCompat;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
index cde72cd..d256830 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
@@ -23,11 +23,11 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.Computer;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 69fb22c..1fe82f4 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -22,8 +22,8 @@
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.trust.TrustManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.DisplayManagerInternal;
@@ -796,18 +796,19 @@
}
if (mActivityManagerInternal.isSystemReady()) {
- mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
- AppOpsManager.OP_NONE, mScreenOnOptions, mWakeUpBroadcastDone, mHandler,
- 0, null, null);
+ final boolean ordered = !mActivityManagerInternal.isModernQueueEnabled();
+ mActivityManagerInternal.broadcastIntent(mScreenOnIntent, mWakeUpBroadcastDone,
+ null, ordered, UserHandle.USER_ALL, null, null, mScreenOnOptions);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
}
}
- private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
+ private final IIntentReceiver mWakeUpBroadcastDone = new IIntentReceiver.Stub() {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky, int sendingUser) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast();
@@ -820,18 +821,19 @@
}
if (mActivityManagerInternal.isSystemReady()) {
- mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
- AppOpsManager.OP_NONE, mScreenOffOptions, mGoToSleepBroadcastDone, mHandler,
- 0, null, null);
+ final boolean ordered = !mActivityManagerInternal.isModernQueueEnabled();
+ mActivityManagerInternal.broadcastIntent(mScreenOffIntent, mGoToSleepBroadcastDone,
+ null, ordered, UserHandle.USER_ALL, null, null, mScreenOffOptions);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
sendNextBroadcast();
}
}
- private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
+ private final IIntentReceiver mGoToSleepBroadcastDone = new IIntentReceiver.Stub() {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky, int sendingUser) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast();
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 1e5b498..916df89 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -99,8 +99,6 @@
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -130,6 +128,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsStore.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsStore.java
index 50cb33c..0d7a140 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsStore.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsStore.java
@@ -25,11 +25,11 @@
import android.util.Log;
import android.util.LongArray;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/sensorprivacy/AllSensorStateController.java b/services/core/java/com/android/server/sensorprivacy/AllSensorStateController.java
index f797f09..58b2443 100644
--- a/services/core/java/com/android/server/sensorprivacy/AllSensorStateController.java
+++ b/services/core/java/com/android/server/sensorprivacy/AllSensorStateController.java
@@ -21,13 +21,13 @@
import android.os.Handler;
import android.util.AtomicFile;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.IoThread;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/sensorprivacy/PersistedState.java b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
index e79efdb8..85ec101 100644
--- a/services/core/java/com/android/server/sensorprivacy/PersistedState.java
+++ b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
@@ -28,14 +28,14 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.QuadConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index fc77ef1..dad3a78 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -47,11 +47,11 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseLongArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.Installer;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java
index 72556a7..f8a9988 100644
--- a/services/core/java/com/android/server/tv/PersistentDataStore.java
+++ b/services/core/java/com/android/server/tv/PersistentDataStore.java
@@ -26,11 +26,11 @@
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
index 7f49eea..39df450 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
@@ -20,10 +20,10 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 6aa06e8..01fdc88 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -71,14 +71,14 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 5f420bf..abb57bc 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -99,8 +99,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
import android.view.DisplayInfo;
@@ -111,6 +109,8 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.JournaledFile;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 81bb3a1..17a9a63 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -312,8 +312,6 @@
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.TimeUtils;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
import android.view.DisplayInfo;
@@ -349,6 +347,8 @@
import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.PendingIntentRecord;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 416d546..ecc43f7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -460,7 +460,6 @@
KeyguardController mKeyguardController;
private final ClientLifecycleManager mLifecycleManager;
- @Nullable
final BackNavigationController mBackNavigationController;
private TaskChangeNotificationController mTaskChangeNotificationController;
@@ -847,8 +846,7 @@
mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
mTaskFragmentOrganizerController =
mWindowOrganizerController.mTaskFragmentOrganizerController;
- mBackNavigationController = BackNavigationController.isEnabled()
- ? new BackNavigationController() : null;
+ mBackNavigationController = new BackNavigationController();
}
public void onSystemReady() {
@@ -1031,9 +1029,7 @@
mLockTaskController.setWindowManager(wm);
mTaskSupervisor.setWindowManager(wm);
mRootWindowContainer.setWindowManager(wm);
- if (mBackNavigationController != null) {
- mBackNavigationController.setWindowManager(wm);
- }
+ mBackNavigationController.setWindowManager(wm);
}
}
@@ -1852,9 +1848,6 @@
IWindowFocusObserver observer, BackAnimationAdapter adapter) {
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"startBackNavigation()");
- if (mBackNavigationController == null) {
- return null;
- }
return mBackNavigationController.startBackNavigation(observer, adapter);
}
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index 5a24099..d22c38e 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -31,10 +31,11 @@
import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 30399ed..1cb83f12 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -65,12 +65,12 @@
// TODO (b/241808055) Find a appropriate time to remove during refactor
// Execute back animation with legacy transition system. Temporary flag for easier debugging.
static final boolean ENABLE_SHELL_TRANSITIONS = WindowManagerService.sEnableShellTransitions;
+
/**
- * Returns true if the back predictability feature is enabled
+ * true if the back predictability feature is enabled
*/
- static boolean isEnabled() {
- return SystemProperties.getInt("persist.wm.debug.predictive_back", 1) != 0;
- }
+ static final boolean sPredictBackEnable =
+ SystemProperties.getBoolean("persist.wm.debug.predictive_back", true);
static boolean isScreenshotEnabled() {
return SystemProperties.getInt("persist.wm.debug.predictive_back_screenshot", 0) != 0;
@@ -88,6 +88,9 @@
@Nullable
BackNavigationInfo startBackNavigation(
IWindowFocusObserver observer, BackAnimationAdapter adapter) {
+ if (!sPredictBackEnable) {
+ return null;
+ }
final WindowManagerService wmService = mWindowManagerService;
mFocusObserver = observer;
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 6f19450..a035948 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -44,11 +44,11 @@
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 4a70fa3..1abb0a1 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -30,14 +30,14 @@
import android.os.Environment;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.DisplayAddress;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index bf4b65d..3a8fbbb 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -173,6 +173,7 @@
mWindowContainer = windowContainer;
// TODO: remove the frame provider for non-WindowState container.
mFrameProvider = frameProvider;
+ mOverrideFrames.clear();
mOverrideFrameProviders = overrideFrameProviders;
if (windowContainer == null) {
setServerVisible(false);
@@ -234,6 +235,8 @@
updateSourceFrameForServerVisibility();
if (mOverrideFrameProviders != null) {
+ // Not necessary to clear the mOverrideFrames here. It will be cleared every time the
+ // override frame provider updates.
for (int i = mOverrideFrameProviders.size() - 1; i >= 0; i--) {
final int windowType = mOverrideFrameProviders.keyAt(i);
final Rect overrideFrame;
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index be3ceb8..bf511adf0 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -27,12 +27,12 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.pm.PackageList;
import com.android.server.wm.LaunchParamsController.LaunchParams;
diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java
index 16f4377..18a7d2e 100644
--- a/services/core/java/com/android/server/wm/PackageConfigPersister.java
+++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java
@@ -23,12 +23,12 @@
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d8b5d78..0ed4835 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -840,11 +840,8 @@
if (recentsAnimationController != null) {
recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
}
- final BackNavigationController backNavigationController =
- mWmService.mAtmService.mBackNavigationController;
- if (backNavigationController != null) {
- backNavigationController.checkAnimationReady(defaultDisplay.mWallpaperController);
- }
+ mWmService.mAtmService.mBackNavigationController
+ .checkAnimationReady(defaultDisplay.mWallpaperController);
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 391d081..e29e3a2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -171,8 +171,6 @@
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.InsetsState;
@@ -197,6 +195,8 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 867833a..509b1e6 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -184,19 +184,30 @@
}
void dispose() {
- while (!mOrganizedTaskFragments.isEmpty()) {
- final TaskFragment taskFragment = mOrganizedTaskFragments.get(0);
- // Cleanup before remove to prevent it from sending any additional event, such as
- // #onTaskFragmentVanished, to the removed organizer.
+ for (int i = mOrganizedTaskFragments.size() - 1; i >= 0; i--) {
+ // Cleanup the TaskFragmentOrganizer from all TaskFragments it organized before
+ // removing the windows to prevent it from adding any additional TaskFragment
+ // pending event.
+ final TaskFragment taskFragment = mOrganizedTaskFragments.get(i);
taskFragment.onTaskFragmentOrganizerRemoved();
- taskFragment.removeImmediately();
- mOrganizedTaskFragments.remove(taskFragment);
}
+
+ // Defer to avoid unnecessary layout when there are multiple TaskFragments removal.
+ mAtmService.deferWindowLayout();
+ try {
+ while (!mOrganizedTaskFragments.isEmpty()) {
+ final TaskFragment taskFragment = mOrganizedTaskFragments.remove(0);
+ taskFragment.removeImmediately();
+ }
+ } finally {
+ mAtmService.continueWindowLayout();
+ }
+
for (int i = mDeferredTransitions.size() - 1; i >= 0; i--) {
// Cleanup any running transaction to unblock the current transition.
onTransactionFinished(mDeferredTransitions.keyAt(i));
}
- mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
+ mOrganizer.asBinder().unlinkToDeath(this, 0 /* flags */);
}
@NonNull
@@ -426,7 +437,6 @@
@Override
public void unregisterOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
- validateAndGetState(organizer);
final int pid = Binder.getCallingPid();
final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
@@ -607,6 +617,13 @@
int opType, @NonNull Throwable exception) {
validateAndGetState(organizer);
Slog.w(TAG, "onTaskFragmentError ", exception);
+ final PendingTaskFragmentEvent vanishedEvent = taskFragment != null
+ ? getPendingTaskFragmentEvent(taskFragment, PendingTaskFragmentEvent.EVENT_VANISHED)
+ : null;
+ if (vanishedEvent != null) {
+ // No need to notify if the TaskFragment has been removed.
+ return;
+ }
addPendingEvent(new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_ERROR, organizer)
.setErrorCallbackToken(errorCallbackToken)
@@ -690,11 +707,17 @@
}
private void removeOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
- final TaskFragmentOrganizerState state = validateAndGetState(organizer);
+ final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(
+ organizer.asBinder());
+ if (state == null) {
+ Slog.w(TAG, "The organizer has already been removed.");
+ return;
+ }
+ // Remove any pending event of this organizer first because state.dispose() may trigger
+ // event dispatch as result of surface placement.
+ mPendingTaskFragmentEvents.remove(organizer.asBinder());
// remove all of the children of the organized TaskFragment
state.dispose();
- // Remove any pending event of this organizer.
- mPendingTaskFragmentEvents.remove(organizer.asBinder());
mTaskFragmentOrganizerState.remove(organizer.asBinder());
}
@@ -878,23 +901,6 @@
return null;
}
- private boolean shouldSendEventWhenTaskInvisible(@NonNull PendingTaskFragmentEvent event) {
- if (event.mEventType == PendingTaskFragmentEvent.EVENT_ERROR
- // Always send parent info changed to update task visibility
- || event.mEventType == PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED) {
- return true;
- }
-
- final TaskFragmentOrganizerState state =
- mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder());
- final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment);
- final TaskFragmentInfo info = event.mTaskFragment.getTaskFragmentInfo();
- // Send an info changed callback if this event is for the last activities to finish in a
- // TaskFragment so that the {@link TaskFragmentOrganizer} can delete this TaskFragment.
- return event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED
- && lastInfo != null && lastInfo.hasRunningActivity() && info.isEmpty();
- }
-
void dispatchPendingEvents() {
if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
|| mPendingTaskFragmentEvents.isEmpty()) {
@@ -908,37 +914,19 @@
}
}
- void dispatchPendingEvents(@NonNull TaskFragmentOrganizerState state,
+ private void dispatchPendingEvents(@NonNull TaskFragmentOrganizerState state,
@NonNull List<PendingTaskFragmentEvent> pendingEvents) {
if (pendingEvents.isEmpty()) {
return;
}
-
- final ArrayList<Task> visibleTasks = new ArrayList<>();
- final ArrayList<Task> invisibleTasks = new ArrayList<>();
- final ArrayList<PendingTaskFragmentEvent> candidateEvents = new ArrayList<>();
- for (int i = 0, n = pendingEvents.size(); i < n; i++) {
- final PendingTaskFragmentEvent event = pendingEvents.get(i);
- final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
- // TODO(b/251132298): move visibility check to the client side.
- if (task != null && (task.lastActiveTime <= event.mDeferTime
- || !(isTaskVisible(task, visibleTasks, invisibleTasks)
- || shouldSendEventWhenTaskInvisible(event)))) {
- // Defer sending events to the TaskFragment until the host task is active again.
- event.mDeferTime = task.lastActiveTime;
- continue;
- }
- candidateEvents.add(event);
- }
- final int numEvents = candidateEvents.size();
- if (numEvents == 0) {
+ if (shouldDeferPendingEvents(state, pendingEvents)) {
return;
}
-
mTmpTaskSet.clear();
+ final int numEvents = pendingEvents.size();
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
for (int i = 0; i < numEvents; i++) {
- final PendingTaskFragmentEvent event = candidateEvents.get(i);
+ final PendingTaskFragmentEvent event = pendingEvents.get(i);
if (event.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED
|| event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED) {
final Task task = event.mTaskFragment.getTask();
@@ -954,7 +942,47 @@
}
mTmpTaskSet.clear();
state.dispatchTransaction(transaction);
- pendingEvents.removeAll(candidateEvents);
+ pendingEvents.clear();
+ }
+
+ /**
+ * Whether or not to defer sending the events to the organizer to avoid waking the app process
+ * when it is in background. We want to either send all events or none to avoid inconsistency.
+ */
+ private boolean shouldDeferPendingEvents(@NonNull TaskFragmentOrganizerState state,
+ @NonNull List<PendingTaskFragmentEvent> pendingEvents) {
+ final ArrayList<Task> visibleTasks = new ArrayList<>();
+ final ArrayList<Task> invisibleTasks = new ArrayList<>();
+ for (int i = 0, n = pendingEvents.size(); i < n; i++) {
+ final PendingTaskFragmentEvent event = pendingEvents.get(i);
+ if (event.mEventType != PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED
+ && event.mEventType != PendingTaskFragmentEvent.EVENT_INFO_CHANGED
+ && event.mEventType != PendingTaskFragmentEvent.EVENT_APPEARED) {
+ // Send events for any other types.
+ return false;
+ }
+
+ // Check if we should send the event given the Task visibility and events.
+ final Task task;
+ if (event.mEventType == PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED) {
+ task = event.mTask;
+ } else {
+ task = event.mTaskFragment.getTask();
+ }
+ if (task.lastActiveTime > event.mDeferTime
+ && isTaskVisible(task, visibleTasks, invisibleTasks)) {
+ // Send events when the app has at least one visible Task.
+ return false;
+ } else if (shouldSendEventWhenTaskInvisible(task, state, event)) {
+ // Sent events even if the Task is invisible.
+ return false;
+ }
+
+ // Defer sending events to the organizer until the host task is active (visible) again.
+ event.mDeferTime = task.lastActiveTime;
+ }
+ // Defer for invisible Task.
+ return true;
}
private static boolean isTaskVisible(@NonNull Task task,
@@ -975,6 +1003,28 @@
}
}
+ private boolean shouldSendEventWhenTaskInvisible(@NonNull Task task,
+ @NonNull TaskFragmentOrganizerState state,
+ @NonNull PendingTaskFragmentEvent event) {
+ final TaskFragmentParentInfo lastParentInfo = state.mLastSentTaskFragmentParentInfos
+ .get(task.mTaskId);
+ if (lastParentInfo == null || lastParentInfo.isVisible()) {
+ // When the Task was visible, or when there was no Task info changed sent (in which case
+ // the organizer will consider it as visible by default), always send the event to
+ // update the Task visibility.
+ return true;
+ }
+ if (event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED) {
+ // Send info changed if the TaskFragment is becoming empty/non-empty so the
+ // organizer can choose whether or not to remove the TaskFragment.
+ final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos
+ .get(event.mTaskFragment);
+ final boolean isEmpty = event.mTaskFragment.getNonFinishingActivityCount() == 0;
+ return lastInfo == null || lastInfo.isEmpty() != isEmpty;
+ }
+ return false;
+ }
+
void dispatchPendingInfoChangedEvent(@NonNull TaskFragment taskFragment) {
final PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment,
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 09fd900..29c192c 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -30,12 +30,12 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 81d6795..6522d93 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -239,8 +239,7 @@
private boolean isBackNavigationTarget(WindowState w) {
// The window is in animating by back navigation and set to show wallpaper.
- final BackNavigationController controller = mService.mAtmService.mBackNavigationController;
- return controller != null && controller.isWallpaperVisible(w);
+ return mService.mAtmService.mBackNavigationController.isWallpaperVisible(w);
}
/**
@@ -831,9 +830,7 @@
// If there was a pending back navigation animation that would show wallpaper, start
// the animation due to it was skipped in previous surface placement.
- if (mService.mAtmService.mBackNavigationController != null) {
- mService.mAtmService.mBackNavigationController.startAnimation();
- }
+ mService.mAtmService.mBackNavigationController.startAnimation();
return true;
}
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 222a96d..8047a53 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -47,11 +47,11 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.UserRestrictionsUtils;
import com.android.server.utils.Slogf;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
index cc32c4d..953a9ee 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
@@ -27,10 +27,11 @@
import android.os.Environment;
import android.util.AtomicFile;
import android.util.Log;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 0305c35..8e430b3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -29,12 +29,12 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.utils.Slogf;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a561307..70422bb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -332,8 +332,6 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -363,6 +361,8 @@
import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.PasswordValidationError;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.ProxyUtils;
import com.android.server.AlarmManagerInternal;
import com.android.server.LocalServices;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index 2ab5464..3040af2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -27,11 +27,11 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
index 289ed36..035f762 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
@@ -24,12 +24,12 @@
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
index ad652df..65b99c5 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
@@ -20,9 +20,9 @@
import android.os.UserHandle
import android.util.ArrayMap
import android.util.SparseArray
-import android.util.TypedXmlPullParser
-import android.util.TypedXmlSerializer
import android.util.Xml
+import com.android.modules.utils.TypedXmlPullParser
+import com.android.modules.utils.TypedXmlSerializer
import com.android.server.pm.verify.domain.DomainVerificationPersistence
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState
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 b7e66f2..ba414cb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -26,6 +26,8 @@
import static com.android.server.am.BroadcastQueueTest.getUidForPackage;
import static com.android.server.am.BroadcastQueueTest.makeManifestReceiver;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -278,7 +280,7 @@
final long notCachedRunnableAt = queue.getRunnableAt();
queue.setProcessCached(true);
final long cachedRunnableAt = queue.getRunnableAt();
- assertTrue(cachedRunnableAt > notCachedRunnableAt);
+ assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertEquals(ProcessList.SCHED_GROUP_BACKGROUND, queue.getPreferredSchedulingGroupLocked());
}
@@ -306,13 +308,13 @@
// (b) the next one up is the fg-priority broadcast despite its later enqueue time
queue.setProcessCached(false);
assertTrue(queue.isRunnable());
- assertEquals(airplaneRecord.enqueueTime, queue.getRunnableAt());
+ assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked());
assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord);
queue.setProcessCached(true);
assertTrue(queue.isRunnable());
- assertEquals(airplaneRecord.enqueueTime, queue.getRunnableAt());
+ assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked());
assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord);
}
@@ -356,12 +358,12 @@
mConstants.MAX_PENDING_BROADCASTS = 128;
queue.invalidateRunnableAt();
- assertTrue(queue.getRunnableAt() > airplaneRecord.enqueueTime);
+ assertThat(queue.getRunnableAt()).isGreaterThan(airplaneRecord.enqueueTime);
assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
mConstants.MAX_PENDING_BROADCASTS = 1;
queue.invalidateRunnableAt();
- assertTrue(queue.getRunnableAt() == airplaneRecord.enqueueTime);
+ assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueTime);
assertEquals(BroadcastProcessQueue.REASON_MAX_PENDING, queue.getRunnableAtReason());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index 7111047..e08a715 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -36,13 +36,14 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index e28d331..28c78b2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -22,6 +22,7 @@
import android.content.pm.VersionedPackage
import android.os.Build
import android.os.storage.StorageManager
+import android.os.UserHandle
import android.util.ArrayMap
import android.util.PackageUtils
import com.android.server.SystemConfig.SharedLibraryEntry
@@ -222,10 +223,11 @@
val parsedPackage = pair.second as ParsedPackage
val scanRequest = ScanRequest(parsedPackage, null, null, null, null,
null, null, null, 0, 0, false, null, null)
- val scanResult = ScanResult(scanRequest, true, null, null, false, 0, null, null, null)
+ val scanResult = ScanResult(scanRequest, null, null, false, 0, null, null, null)
+ var installRequest = InstallRequest(parsedPackage, 0, 0, UserHandle(0), scanResult)
val latestInfoSetting =
- mSharedLibrariesImpl.getStaticSharedLibLatestVersionSetting(scanResult)!!
+ mSharedLibrariesImpl.getStaticSharedLibLatestVersionSetting(installRequest)!!
assertThat(latestInfoSetting).isNotNull()
assertThat(latestInfoSetting.packageName).isEqualTo(STATIC_LIB_PACKAGE_NAME)
@@ -305,10 +307,11 @@
@Test
fun getAllowedSharedLibInfos_withStaticSharedLibInfo() {
val testInfo = libOfStatic(TEST_LIB_PACKAGE_NAME, TEST_LIB_NAME, 1L)
- val scanResult = ScanResult(mock(), true, null, null,
+ val scanResult = ScanResult(mock(), null, null,
false, 0, null, testInfo, null)
+ var installRequest = InstallRequest(mock(), 0, 0, UserHandle(0), scanResult)
- val allowedInfos = mSharedLibrariesImpl.getAllowedSharedLibInfos(scanResult)
+ val allowedInfos = mSharedLibrariesImpl.getAllowedSharedLibInfos(installRequest)
assertThat(allowedInfos).hasSize(1)
assertThat(allowedInfos[0].name).isEqualTo(TEST_LIB_NAME)
@@ -327,10 +330,11 @@
.setPkgFlags(ApplicationInfo.FLAG_SYSTEM).build()
val scanRequest = ScanRequest(parsedPackage, null, null, null, null,
null, null, null, 0, 0, false, null, null)
- val scanResult = ScanResult(scanRequest, true, packageSetting, null,
+ val scanResult = ScanResult(scanRequest, packageSetting, null,
false, 0, null, null, listOf(testInfo))
+ var installRequest = InstallRequest(parsedPackage, 0, 0, UserHandle(0), scanResult)
- val allowedInfos = mSharedLibrariesImpl.getAllowedSharedLibInfos(scanResult)
+ val allowedInfos = mSharedLibrariesImpl.getAllowedSharedLibInfos(installRequest)
assertThat(allowedInfos).hasSize(1)
assertThat(allowedInfos[0].name).isEqualTo(TEST_LIB_NAME)
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 5fb3a4e..7fd1ddb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -69,8 +69,6 @@
import android.testing.TestableContext;
import android.util.Log;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -80,6 +78,8 @@
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.R;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.wallpaper.WallpaperManagerService.WallpaperData;
import com.android.server.wm.WindowManagerInternal;
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index b33e22f..9acc4bd 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -49,13 +49,13 @@
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.AtomicFile;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.widget.RemoteViews;
import com.android.frameworks.servicestests.R;
import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import org.mockito.ArgumentCaptor;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
index 68c9ce4..0cff4f1 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
@@ -178,6 +178,23 @@
}
@Test
+ public void testWatchDogCompletesAwait() {
+ mProbe.enable();
+
+ AtomicInteger lux = new AtomicInteger(-9);
+ mProbe.awaitNextLux((v) -> lux.set(Math.round(v)), null /* handler */);
+
+ verify(mSensorManager).registerListener(
+ mSensorEventListenerCaptor.capture(), any(), anyInt());
+
+ moveTimeBy(TIMEOUT_MS);
+
+ assertThat(lux.get()).isEqualTo(-1);
+ verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
+ verifyNoMoreInteractions(mSensorManager);
+ }
+
+ @Test
public void testNextLuxWhenAlreadyEnabledAndNotAvailable() {
testNextLuxWhenAlreadyEnabled(false /* dataIsAvailable */);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
index d58d71f..dc46ff8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
@@ -23,13 +23,13 @@
import android.app.admin.FactoryResetProtectionPolicy;
import android.os.Parcel;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.FastXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 72fac55..d540734 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -33,12 +33,12 @@
import android.os.IpcDataCache;
import android.os.Parcel;
import android.os.UserHandle;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import com.android.internal.util.JournaledFile;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.SystemService;
import com.google.common.io.Files;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index 1308a3e..7588c79d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -29,13 +29,13 @@
import android.app.admin.FreezePeriod;
import android.app.admin.SystemUpdatePolicy;
import android.os.Parcel;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.FastXmlSerializer;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
index c735d18..8f0fb0b 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
@@ -45,14 +45,14 @@
import android.os.RemoteException;
import android.os.SimpleClock;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.After;
import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
index 853eea1..ee97466 100644
--- a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
@@ -44,13 +44,13 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AtomicFile;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.wm.ActivityTaskManagerInternal;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index 0a26f27..3f7eac7 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -29,12 +29,13 @@
import android.content.om.OverlayIdentifier;
import android.content.om.OverlayInfo;
import android.text.TextUtils;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import androidx.annotation.NonNull;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index a545b1f..648f895 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -32,13 +32,13 @@
import android.platform.test.annotations.Presubmit;
import android.util.AtomicFile;
import android.util.Slog;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BackgroundThread;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index 7e4474f..47f75a5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -25,13 +25,13 @@
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.platform.test.annotations.Presubmit;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.HexDump;
+import com.android.modules.utils.TypedXmlPullParser;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 4d03749..48d6d90 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -568,7 +568,6 @@
private static void assertBasicPackageScanResult(
ScanResult scanResult, String packageName, boolean isInstant) {
- assertThat(scanResult.mSuccess, is(true));
final PackageSetting pkgSetting = scanResult.mPkgSetting;
assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
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 867890f..96c0d0a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -98,13 +98,13 @@
import android.platform.test.annotations.Presubmit;
import android.util.Log;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.filters.SmallTest;
import com.android.frameworks.servicestests.R;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
import com.android.server.pm.ShortcutUser.PackageWithUser;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index 13a7a3e..8efcc41 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -23,13 +23,14 @@
import android.content.pm.UserProperties;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java
index 1049274..970020f 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java
@@ -27,13 +27,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.PowerProfile;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
index 067f4e2..e603ea5 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
@@ -37,13 +37,14 @@
import android.os.Parcel;
import android.os.UidBatteryConsumer;
import android.os.UserBatteryConsumer;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
index 7ac4938..9c61d95 100644
--- a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
@@ -21,10 +21,10 @@
import android.app.usage.CacheQuotaHint;
import android.test.AndroidTestCase;
import android.util.Pair;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import com.android.modules.utils.TypedXmlSerializer;
import org.junit.Before;
import org.junit.Test;
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 7986043..582e744 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -62,11 +62,11 @@
import android.util.ArraySet;
import android.util.IntArray;
import android.util.SparseArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.google.android.collect.Lists;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 4b93e35..9c68ddc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -46,10 +46,10 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.util.function.TriPredicate;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 248a3fc..581cf43 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -63,10 +63,10 @@
import android.testing.TestableContext;
import android.util.ArraySet;
import android.util.Pair;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.google.common.collect.ImmutableList;
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 92761427..2ed8b10 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -193,8 +193,6 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Pair;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.widget.RemoteViews;
@@ -206,6 +204,8 @@
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
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 598a22b..0f93598 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -110,14 +110,14 @@
import android.util.IntArray;
import android.util.Pair;
import android.util.StatsEvent;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.os.AtomsProto.PackageNotificationPreferences;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.PermissionHelper.PackagePermission;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 7817e81..a03a1b4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -44,12 +44,12 @@
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.IntArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.android.server.pm.PackageManagerService;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 949455a1..2b6db14 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -33,12 +33,12 @@
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenPolicy;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.UiServiceTestCase;
import org.junit.Test;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 2ccdcaa..49edde5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -105,12 +105,12 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.StatsEvent;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.ManagedServices.UserProfiles;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 18a1caa..9d839fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -29,7 +29,6 @@
import android.annotation.Nullable;
import android.platform.test.annotations.Presubmit;
-import android.util.TypedXmlPullParser;
import android.util.Xml;
import android.view.Display;
import android.view.DisplayAddress;
@@ -37,6 +36,7 @@
import androidx.test.filters.SmallTest;
+import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
import org.junit.After;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 0b23359..4202f46 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -56,6 +56,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -91,6 +92,7 @@
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import java.util.List;
@@ -762,6 +764,50 @@
}
@Test
+ public void testOrganizerRemovedWithPendingEvents() {
+ final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
+ .setCreateParentTask()
+ .setOrganizer(mOrganizer)
+ .setFragmentToken(mFragmentToken)
+ .build();
+ final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
+ .setCreateParentTask()
+ .setOrganizer(mOrganizer)
+ .setFragmentToken(new Binder())
+ .build();
+ assertTrue(tf0.isOrganizedTaskFragment());
+ assertTrue(tf1.isOrganizedTaskFragment());
+ assertTrue(tf0.isAttached());
+ assertTrue(tf0.isAttached());
+
+ // Mock the behavior that remove TaskFragment can trigger event dispatch.
+ final Answer<Void> removeImmediately = invocation -> {
+ invocation.callRealMethod();
+ mController.dispatchPendingEvents();
+ return null;
+ };
+ doAnswer(removeImmediately).when(tf0).removeImmediately();
+ doAnswer(removeImmediately).when(tf1).removeImmediately();
+
+ // Add pending events.
+ mController.onTaskFragmentAppeared(mIOrganizer, tf0);
+ mController.onTaskFragmentAppeared(mIOrganizer, tf1);
+
+ // Remove organizer.
+ mController.unregisterOrganizer(mIOrganizer);
+ mController.dispatchPendingEvents();
+
+ // Nothing should happen after the organizer is removed.
+ verify(mOrganizer, never()).onTransactionReady(any());
+
+ // TaskFragments should be removed.
+ assertFalse(tf0.isOrganizedTaskFragment());
+ assertFalse(tf1.isOrganizedTaskFragment());
+ assertFalse(tf0.isAttached());
+ assertFalse(tf0.isAttached());
+ }
+
+ @Test
public void testTaskFragmentInPip_startActivityInTaskFragment() {
setupTaskFragmentInPip();
final ActivityRecord activity = mTaskFragment.getTopMostActivity();
@@ -874,29 +920,87 @@
@Test
public void testDeferPendingTaskFragmentEventsOfInvisibleTask() {
- // Task - TaskFragment - Activity.
final Task task = createTask(mDisplayContent);
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
.setOrganizer(mOrganizer)
.setFragmentToken(mFragmentToken)
.build();
-
- // Mock the task to invisible
doReturn(false).when(task).shouldBeVisible(any());
- // Sending events
- taskFragment.mTaskFragmentAppearedSent = true;
+ // Dispatch the initial event in the Task to update the Task visibility to the organizer.
+ mController.onTaskFragmentAppeared(mIOrganizer, taskFragment);
+ mController.dispatchPendingEvents();
+ verify(mOrganizer).onTransactionReady(any());
+
+ // Verify that events were not sent when the Task is in background.
+ clearInvocations(mOrganizer);
+ final Rect bounds = new Rect(0, 0, 500, 1000);
+ task.setBoundsUnchecked(bounds);
+ mController.onTaskFragmentParentInfoChanged(mIOrganizer, task);
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
-
- // Verifies that event was not sent
verify(mOrganizer, never()).onTransactionReady(any());
+
+ // Verify that the events were sent when the Task becomes visible.
+ doReturn(true).when(task).shouldBeVisible(any());
+ task.lastActiveTime++;
+ mController.dispatchPendingEvents();
+ verify(mOrganizer).onTransactionReady(any());
+ }
+
+ @Test
+ public void testSendAllPendingTaskFragmentEventsWhenAnyTaskIsVisible() {
+ // Invisible Task.
+ final Task invisibleTask = createTask(mDisplayContent);
+ final TaskFragment invisibleTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(invisibleTask)
+ .setOrganizer(mOrganizer)
+ .setFragmentToken(mFragmentToken)
+ .build();
+ doReturn(false).when(invisibleTask).shouldBeVisible(any());
+
+ // Visible Task.
+ final IBinder fragmentToken = new Binder();
+ final Task visibleTask = createTask(mDisplayContent);
+ final TaskFragment visibleTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(visibleTask)
+ .setOrganizer(mOrganizer)
+ .setFragmentToken(fragmentToken)
+ .build();
+ doReturn(true).when(invisibleTask).shouldBeVisible(any());
+
+ // Sending events
+ invisibleTaskFragment.mTaskFragmentAppearedSent = true;
+ visibleTaskFragment.mTaskFragmentAppearedSent = true;
+ mController.onTaskFragmentInfoChanged(mIOrganizer, invisibleTaskFragment);
+ mController.onTaskFragmentInfoChanged(mIOrganizer, visibleTaskFragment);
+ mController.dispatchPendingEvents();
+
+ // Verify that both events are sent.
+ verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
+ final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
+ final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
+
+ // There should be two Task info changed with two TaskFragment info changed.
+ assertEquals(4, changes.size());
+ // Invisible Task info changed
+ assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, changes.get(0).getType());
+ assertEquals(invisibleTask.mTaskId, changes.get(0).getTaskId());
+ // Invisible TaskFragment info changed
+ assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, changes.get(1).getType());
+ assertEquals(invisibleTaskFragment.getFragmentToken(),
+ changes.get(1).getTaskFragmentToken());
+ // Visible Task info changed
+ assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, changes.get(2).getType());
+ assertEquals(visibleTask.mTaskId, changes.get(2).getTaskId());
+ // Visible TaskFragment info changed
+ assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, changes.get(3).getType());
+ assertEquals(visibleTaskFragment.getFragmentToken(), changes.get(3).getTaskFragmentToken());
}
@Test
public void testCanSendPendingTaskFragmentEventsAfterActivityResumed() {
- // Task - TaskFragment - Activity.
final Task task = createTask(mDisplayContent);
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
@@ -905,24 +1009,26 @@
.createActivityCount(1)
.build();
final ActivityRecord activity = taskFragment.getTopMostActivity();
-
- // Mock the task to invisible
doReturn(false).when(task).shouldBeVisible(any());
taskFragment.setResumedActivity(null, "test");
- // Sending events
- taskFragment.mTaskFragmentAppearedSent = true;
+ // Dispatch the initial event in the Task to update the Task visibility to the organizer.
+ mController.onTaskFragmentAppeared(mIOrganizer, taskFragment);
+ mController.dispatchPendingEvents();
+ verify(mOrganizer).onTransactionReady(any());
+
+ // Verify the info changed event is not sent because the Task is invisible
+ clearInvocations(mOrganizer);
+ final Rect bounds = new Rect(0, 0, 500, 1000);
+ task.setBoundsUnchecked(bounds);
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
-
- // Verifies that event was not sent
verify(mOrganizer, never()).onTransactionReady(any());
- // Mock the task becomes visible, and activity resumed
+ // Mock the task becomes visible, and activity resumed. Verify the info changed event is
+ // sent.
doReturn(true).when(task).shouldBeVisible(any());
taskFragment.setResumedActivity(activity, "test");
-
- // Verifies that event is sent.
mController.dispatchPendingEvents();
verify(mOrganizer).onTransactionReady(any());
}
@@ -977,25 +1083,24 @@
final ActivityRecord embeddedActivity = taskFragment.getTopNonFinishingActivity();
// Add another activity in the Task so that it always contains a non-finishing activity.
createActivityRecord(task);
- assertTrue(task.shouldBeVisible(null));
+ doReturn(false).when(task).shouldBeVisible(any());
- // Dispatch pending info changed event from creating the activity
- taskFragment.mTaskFragmentAppearedSent = true;
- mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
+ // Dispatch the initial event in the Task to update the Task visibility to the organizer.
+ mController.onTaskFragmentAppeared(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
verify(mOrganizer).onTransactionReady(any());
- // Verify the info changed callback is not called when the task is invisible
+ // Verify the info changed event is not sent because the Task is invisible
clearInvocations(mOrganizer);
- doReturn(false).when(task).shouldBeVisible(any());
+ final Rect bounds = new Rect(0, 0, 500, 1000);
+ task.setBoundsUnchecked(bounds);
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
verify(mOrganizer, never()).onTransactionReady(any());
- // Finish the embedded activity, and verify the info changed callback is called because the
+ // Finish the embedded activity, and verify the info changed event is sent because the
// TaskFragment is becoming empty.
embeddedActivity.finishing = true;
- mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
verify(mOrganizer).onTransactionReady(any());
}
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 92c9e80..66bf78b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -77,14 +77,15 @@
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
import android.view.DisplayInfo;
import androidx.test.filters.MediumTest;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index bb0c4e9..47b09fe 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -53,8 +53,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -62,6 +60,8 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import libcore.io.IoUtils;
diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index dd5f153..f39cb39 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -48,13 +48,13 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseBooleanArray;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 96bbf82..f8d885a 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -44,14 +44,14 @@
import android.provider.DeviceConfig;
import android.util.AtomicFile;
import android.util.LongArrayQueue;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.PackageWatchdog.HealthCheckState;
import com.android.server.PackageWatchdog.MonitoredPackage;
import com.android.server.PackageWatchdog.PackageHealthObserver;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 5cee17e..df09e47 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -30,6 +30,91 @@
namespace aapt {
+// This is to detect whether an <intent-filter> contains deeplink.
+// See https://developer.android.com/training/app-links/deep-linking.
+static bool HasDeepLink(xml::Element* intent_filter_el) {
+ xml::Element* action_el = intent_filter_el->FindChild({}, "action");
+ xml::Element* category_el = intent_filter_el->FindChild({}, "category");
+ xml::Element* data_el = intent_filter_el->FindChild({}, "data");
+ if (action_el == nullptr || category_el == nullptr || data_el == nullptr) {
+ return false;
+ }
+
+ // Deeplinks must specify the ACTION_VIEW intent action.
+ constexpr const char* action_view = "android.intent.action.VIEW";
+ if (intent_filter_el->FindChildWithAttribute({}, "action", xml::kSchemaAndroid, "name",
+ action_view) == nullptr) {
+ return false;
+ }
+
+ // Deeplinks must have scheme included in <data> tag.
+ xml::Attribute* data_scheme_attr = data_el->FindAttribute(xml::kSchemaAndroid, "scheme");
+ if (data_scheme_attr == nullptr || data_scheme_attr->value.empty()) {
+ return false;
+ }
+
+ // Deeplinks must include BROWSABLE category.
+ constexpr const char* category_browsable = "android.intent.category.BROWSABLE";
+ if (intent_filter_el->FindChildWithAttribute({}, "category", xml::kSchemaAndroid, "name",
+ category_browsable) == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static bool VerifyDeeplinkPathAttribute(xml::Element* data_el, android::SourcePathDiagnostics* diag,
+ const std::string& attr_name) {
+ xml::Attribute* attr = data_el->FindAttribute(xml::kSchemaAndroid, attr_name);
+ if (attr != nullptr && !attr->value.empty()) {
+ StringPiece attr_value = attr->value;
+ const char* startChar = attr_value.begin();
+ if (attr_name == "pathPattern") {
+ if (*startChar == '/' || *startChar == '.' || *startChar == '*') {
+ return true;
+ } else {
+ diag->Error(android::DiagMessage(data_el->line_number)
+ << "attribute 'android:" << attr_name << "' in <" << data_el->name
+ << "> tag has value of '" << attr_value
+ << "', it must be in a pattern start with '.' or '*', otherwise must start "
+ "with a leading slash '/'");
+ return false;
+ }
+ } else {
+ if (*startChar == '/') {
+ return true;
+ } else {
+ diag->Error(android::DiagMessage(data_el->line_number)
+ << "attribute 'android:" << attr_name << "' in <" << data_el->name
+ << "> tag has value of '" << attr_value
+ << "', it must start with a leading slash '/'");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool VerifyDeepLinkIntentAction(xml::Element* intent_filter_el,
+ android::SourcePathDiagnostics* diag) {
+ if (!HasDeepLink(intent_filter_el)) {
+ return true;
+ }
+
+ xml::Element* data_el = intent_filter_el->FindChild({}, "data");
+ if (data_el != nullptr) {
+ if (!VerifyDeeplinkPathAttribute(data_el, diag, "path")) {
+ return false;
+ }
+ if (!VerifyDeeplinkPathAttribute(data_el, diag, "pathPrefix")) {
+ return false;
+ }
+ if (!VerifyDeeplinkPathAttribute(data_el, diag, "pathPattern")) {
+ return false;
+ }
+ }
+ return true;
+}
+
static bool RequiredNameIsNotEmpty(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
@@ -323,6 +408,7 @@
// Common <intent-filter> actions.
xml::XmlNodeAction intent_filter_action;
+ intent_filter_action.Action(VerifyDeepLinkIntentAction);
intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
intent_filter_action["data"];
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 098d0be..cec9a1a 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -1068,4 +1068,345 @@
</manifest>)";
EXPECT_THAT(Verify(input), NotNull());
}
+
+TEST_F(ManifestFixerTest, IntentFilterActionMustHaveNonEmptyName) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+}
+
+TEST_F(ManifestFixerTest, IntentFilterCategoryMustHaveNonEmptyName) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category android:name="" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+}
+
+TEST_F(ManifestFixerTest, IntentFilterPathMustStartWithLeadingSlashOnDeepLinks) {
+ // No DeepLink.
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <data />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // No DeepLink, missing ACTION_VIEW.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink, missing DEFAULT category while DEFAULT is recommended but not required.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // No DeepLink, missing BROWSABLE category.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // No DeepLink, missing 'android:scheme' in <data> tag.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // No DeepLink, <action> is ACTION_MAIN not ACTION_VIEW.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with no leading slash in android:path.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:path="path" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // DeepLink with leading slash in android:path.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:path="/path" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with no leading slash in android:pathPrefix.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPrefix" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // DeepLink with leading slash in android:pathPrefix.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="/pathPrefix" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with no leading slash in android:pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // DeepLink with leading slash in android:pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern="/pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with '.' start in pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern=".*\\.pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with '*' start in pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern="*" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+}
} // namespace aapt